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\n", ans);
else puts("No solution");
}
int main(){
while(data_in())
solve();
return 0;
}
