UVALive 6834

购物

题目描述:

给出N个点~1000,就是1到N。然后给出m条边,每个是di到ci,意思是只有到达过di之后到达ci才算到达过ci。求:从1出发,将1到N个点全部搞完然后到N点的总距离。

题解:

很好的一道题。首先发现区间不连续,不能够用dp。然后研究性质,发现:如果di》ci,就增加一个区间ci到di,表明要额外走双份,这样都处理后,发现如果di《ci是不用弄的,因为所有与di和ci有关的都搞过了。之后就是拿着已经增添的区间来搞出要多走两次的部分,其实就是区间覆盖的地方只算一次。
区间覆盖:按左端点排序,然后记录当前左端点不间断到达的最远右处。

重点:

发现有边的需要重复走,并且节省重复走的可以将覆盖的只走一遍,由此启发出解法:将需要重走的搞出区间,然后变成了区间覆盖。

代码:
//晨豪的代码
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1010;
int n,m;
int tot;
int cnt;
struct P
{
    int l,r;
}a[N],b[N];
void init()
{
    tot = cnt = 0;
    for (int i = 1; i <= m; i++)
    {
        int aa,bb;
        scanf("%d %d",&aa,&bb);
        if (bb < aa) continue;
        a[++tot].l = aa;//搞出需要的区间
        a[tot].r = bb;
    }
}
int com(P x,P y)//左端点排序
{
    if (x.l == y.l) return x.r < y.r;
    return x.l < y.l;
}
void solve()
{
    init();
    sort(a+1,a+tot+1,com);
    int ans = n+1;
    int l = a[1].l,r = a[1].r;
    for (int i = 2;i <= tot;i++)//区间覆盖
    {
        if (r < a[i].l)
        {
            b[++cnt].l = l;
            b[cnt].r = r;
            l = a[i].l;
            r = a[i].r;
        }
        else
            r = max(r,a[i].r);
        if (i == tot)
        {
            b[++cnt].l = l;
            b[cnt].r = r;
        }
    }

    for (int i = 1;i <= cnt;i++)
        ans += 2*(b[i].r - b[i].l);
    printf("%d\n",ans);
}
int main()
{
  //  freopen("in.txt","r",stdin);
    while (~scanf("%d %d",&n,&m))
    {
        solve();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值