购物
题目描述:
给出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();
}
}