UVA 1632-Alibaba(DP),uva1632-alibabadp
題目大意:在一條直線上有n(n<=10000)個點有寶藏,每個點的座標都是整數,每個寶藏在某個時間到之後都會消失,可以在任何一個點出發,移動一個單位需要一個單位的時間,問最少需要多少時間拿完所有寶藏,如果不能拿完所有的輸出No solution。輸入按照座標遞增順序。
a[i]表示第i個寶藏的位置,b[i]表示消失的時間。
首先注意到對於任意區間(i,j),拿完所有寶藏之後必然在i或j兩者之一。所以用d[i][j][0]表示拿完第i個到第j個之間的所有寶藏,且最後位於i,用d[i][j][1]表示拿完第i個到第j個之間的所有寶藏且最後位於j。
程式用滾動數組最佳化記憶體消耗,遞推是按照區間的寬度遞增的順序,所以也是按照這樣滾動的。
狀態轉移方程:
d[i][j][0]=min { d[i+1][j][0]+a[i+1]-a[i],d[i+1][j][1]+a[i+j]-a[i]}
d[i][j][1]=min { d[i][j-1][0]+a[i+j]-a[i],d[i][j-1][1]+a[i+j]-a[i+j-1]}
在程式中還需要判斷遞推過程中是否能在消失前到達,不能到達則置為INF。
#include<stdio.h>#include<stdlib.h>int a[10010];int b[10010];int d[2][10010][2];int main(void){int i,j,n,cur,min;while(scanf("%d",&n)==1){for(i=1;i<=n;i++){scanf("%d%d",&a[i],&b[i]);}cur=0;for(j=1;j<=n;j++){d[0][j][0]=d[0][j][1]=(b[j]>0)?0:(1<<30);}for(i=1;i<n;i++){cur^=1;for(j=1;j<=n-i;j++){d[cur][j][0]=d[cur^1][j+1][0]+a[j+1]-a[j]>d[cur^1][j+1][1]+a[j+i]-a[j]?d[cur^1][j+1][1]+a[j+i]-a[j]:d[cur^1][j+1][0]+a[j+1]-a[j];d[cur][j][1]=d[cur^1][j][0]+a[j+i]-a[j]>d[cur^1][j][1]+a[j+i]-a[j+i-1]?d[cur^1][j][1]+a[j+i]-a[j+i-1]:d[cur^1][j][0]+a[j+i]-a[j];d[cur][j][0]=d[cur][j][0]<b[j]?d[cur][j][0]:(1<<30);d[cur][j][1]=d[cur][j][1]<b[j+i]?d[cur][j][1]:(1<<30);}}min=d[cur][1][0]>d[cur][1][1]?d[cur][1][1]:d[cur][1][0];if(min==(1<<30)){printf("No solution\n");}else{printf("%d\n",min);}}return 0;}