UVA-1632 Alibaba (区间DP+滚动数组)

时间:2021-10-27 09:01:37

题目大意:在一条直线上有n件珠宝,已知每件珠宝的位置,并且第 i 件珠宝在 ti 时刻就消失,问能否将所有的珠宝收集起来?如果能,求出最短时间。搜集能瞬间完成。

题目分析:区间DP。dp(i,j,0)表示搜集区间(i,j)并且停留在左端所需的最短时间,dp(i,j,1)表示搜集区间(i,j)并且停留在右端所需的最短时间。状态转移方程为

dp(i,j,0)=min(dp(i+1,j,0)+t(i+1)-t(i),dp(i+1,j1,)+t(j)-t(i)),dp(i,j,1)=min(dp(i,j-1,0)+t(j)-t(i),dp(i,j-1,1)+t(j)-t(j-1))。

这道题的数据规模比较大,可以用滚动数组优化空间复杂度。

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; int dp[2][10005][2];
int x[10005],t[10005],n; const int INF=0x7fffffff; int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;++i){
scanf("%d%d",x+i,t+i);
dp[1][i][0]=dp[1][i][1]=dp[0][i][0]=dp[0][i][1]=(t[i]>0)?0:INF;
} for(int i=n-2;i>=0;--i){
for(int j=i+1;j<n;++j){
dp[i&1][j][0]=dp[i&1][j][1]=INF;
if(dp[(i&1)^1][j][0]!=INF&&dp[(i&1)^1][j][0]+x[i+1]-x[i]<t[i])
dp[i&1][j][0]=min(dp[i&1][j][0],dp[(i&1)^1][j][0]+x[i+1]-x[i]);
if(dp[(i&1)^1][j][1]!=INF&&dp[(i&1)^1][j][1]+x[j]-x[i]<t[i])
dp[i&1][j][0]=min(dp[i&1][j][0],dp[(i&1)^1][j][1]+x[j]-x[i]);
if(dp[i&1][j-1][0]!=INF&&dp[i&1][j-1][0]+x[j]-x[i]<t[j])
dp[i&1][j][1]=min(dp[i&1][j][1],dp[i&1][j-1][0]+x[j]-x[i]);
if(dp[i&1][j-1][1]!=INF&&dp[i&1][j-1][1]+x[j]-x[j-1]<t[j])
dp[i&1][j][1]=min(dp[i&1][j][1],dp[i&1][j-1][1]+x[j]-x[j-1]);
}
}
if(dp[0][n-1][1]==INF&&dp[0][n-1][0]==INF) printf("No solution\n");
else printf("%d\n",min(dp[0][n-1][0],dp[0][n-1][1]));
}
return 0;
}

  

  

下面这个是不加滚动数组的:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; int dp[10005][10005][2];
int x[10005],t[10005],n; const int INF=1000000000; int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;++i)
scanf("%d%d",x+i,t+i),dp[i][i][0]=dp[i][i][1]=0; for(int i=n-2;i>=0;--i){
for(int j=i+1;j<n;++j){
dp[i][j][0]=min(dp[i+1][j][0]+x[i+1]-x[i],dp[i+1][j][1]+x[j]-x[i]);
if(dp[i][j][0]>=t[i]) dp[i][j][0]=INF;
dp[i][j][1]=min(dp[i][j-1][0]+x[j]-x[i],dp[i][j-1][1]+x[j]-x[j-1]);
if(dp[i][j][1]>=t[j]) dp[i][j][1]=INF;
}
}
if(dp[0][n-1][1]==INF&&dp[0][n-1][0]==INF) printf("No solution\n");
else printf("%d\n",min(dp[0][n-1][0],dp[0][n-1][1]));
}
return 0;
}