Description
在一条直线上有 n 件珠宝,已知每件珠宝的位置xi,并且第 i 件珠宝在 ti 时刻(单位:秒)就消失,问能否将所有的珠宝收集起来?如果能,求出最短时间。搜集能瞬间完成,但收集的人每秒只能移动一个单位的距离。
Input
若干组数据,每组数据的第一行为n,表示有n颗珠宝,接下来的n行,每行宝行两个整数:x,t,表示珠宝的位置和消失时间。
Output
如果有解,则输出一个整数,表示将所有珠宝收集完的最早完成时间,否则输出No solution。
Sample Input 1
5 1 3 3 1 5 8 8 19 10 15 5 1 5 2 1 3 4 4 2 5 3
Sample Output 1
11 No solution
Hint
n<=10000
0<=x,t<=10^9
网上分析:
f(i,j,0)表示区间i~j中获得所有宝藏并且停留在左端点,f(i,j,1)停留在右端点
ans=min(f(1,n,0),f(1,n,1))
i=j时,f(i,j,0)=f(i,j,1)=0;
f(i,j,0)=min(f(i+1,j,1)+x[i+1]-x[i],f(i+1,j,0)+x[j]-x[i])
f(i,j,1)=min(f(i,j-1,0)+x[j]-x[j-1],f(i,j-1,1)+x[j]-x[i])
填表的时候需要按照主对角线填入
加一个压行不然会爆空间
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 10005, inf = 0x3f3f3f3f; struct data{ int x; int t; bool operator<(const data &b)const{ return x < b.x; } }a[maxn]; int n; bool data_in(){ if(scanf("%d", &n) == 1){ for(int i=1;i<=n;i++) scanf("%d%d", &a[i].x, &a[i].t); sort(a+1, a+1+n); return true; } else return false; } int f[2][maxn][2]; /* f[i][j][0] = min(f[i+1][j][0]+x[i+1]-x[i], f[i+1][j][1]+x[j]-x[i]) f[i][j][1] = min(f[i][j-1][0]+x[j]-x[i], f[i][j-1][1]+x[j]-x[j-1]) */ void solve(){ memset(f, 0, sizeof(f)); for(int len=2;len<=n;len++) for(int i=1;i+len-1<=n;i++){ int j=i+len-1; f[i&1][j][0] = min(f[(i+1)&1][j][0]+a[i+1].x-a[i].x, f[(i+1)&1][j][1]+a[j].x-a[i].x); if(f[i&1][j][0] >= a[i].t) f[i&1][j][0] = inf; f[i&1][j][1] = min(f[i&1][j-1][0]+a[j].x-a[i].x, f[i&1][j-1][1]+a[j].x-a[j-1].x); if(f[i&1][j][1] >= a[j].t) f[i&1][j][1] = inf; } int ans = min(f[1][n][0], f[1][n][1]); if(ans<inf) printf("%d ", ans); else puts("No solution"); } int main(){ while(data_in()) solve(); return 0; }