题意:在一条路上有 n 个站点,并给定了每个站点的坐标,然后想要在 k 个站点旁边分别各建一个补给站,求所有站点到最近的补给站的距离和的最小值。
是的,毫无疑问,显然是 DP 问题,但是这题怎么递推还是需要考虑的,我一开始是以 dp [ k ] [ i ] 表示设好第 k 个补给站并讨论到第 i 个站点时的最短路径,即第 k 个补给站不一定是设在第 i 个站点的,但是敲了一半我就发现这样做非常麻烦,因为首先我必须记录下每次 dp 时最后一个站点的位置,其次我还要对于每个考虑到的站点分析最后一个补给站设在之前(即从 dp [ k ] [ i - 1 ]转移)或在第 i 站(即从 dp [ k - 1 ] [ i - 1 ]转移并修改中间项的最小距离),所以很快我就意识到我不能这么做,粗看了题解之后我才发现,做法其实应该是我一开始 pass 掉的 dp [ k ] [ i - 1 ] 表示在第 i 站设第 k 个补给站的最短路程,这样只要对于设置最后一个补给站的 dp 值加上剩下没有加的距离,就是最终结果。
就这样,我基本理解了题目的做法,并且敲了一遍,然后就习惯性地 WA 了,昂,基本也属习惯,虽然我也一直在努力纠正,就是在很多我很习惯的模型上我一般不会敲错,但是这些新想的,专对题目的 dp 我却总是会出错,主要就是各种细节,特别是杭电对于各种细节坑非常扣。
这题一点一点比对,才发现,坐标是有负数的,所以最好就是一开始把所有的坐标都弄成非负数,然后 dp 过程中也有各种小错误,一题大概当时做了一天吧,还是很心塞的。
1 #include<stdio.h> 2 #include<string.h> 3 #define min(a,b) a<b?a:b 4 #define INF 0xFFFFFFF 5 6 int a[205],dp[35][205],w[205][205]; 7 8 int main(){ 9 int n,m,c=0; 10 while(scanf("%d%d",&n,&m)!=EOF&&n!=0||m!=0){ 11 int i,j,k,tmp,ans=INF; 12 for(i=1;i<=n;i++){ 13 scanf("%d",&a[i]); 14 } 15 memset(w,0,sizeof(w)); 16 for(i=n;i>=1;i--){ 17 a[i]=a[i]-a[1]+1; 18 } 19 for(i=1;i<=n;i++){ 20 for(j=i;j<=n;j++){ 21 tmp=0; 22 for(k=i;k<=j;k++){ 23 24 tmp+=min(a[k]-a[i],a[j]-a[k]); 25 } 26 w[i][j]=tmp; 27 } 28 } 29 /* 30 printf(" w: "); 31 for(i=1;i<=n;i++){ 32 for(j=1;j<=n;j++){ 33 printf("%3d",w[i][j]); 34 } 35 printf(" "); 36 } 37 printf(" "); 38 */ 39 // printf("min=%d ",min(a[3]-a[2],a[2]-a[1])); 40 41 memset(dp,0,sizeof(dp)); 42 for(i=1;i<=n;i++){ 43 for(j=1;j<=i;j++){ 44 dp[1][i]+=a[i]-a[j]; 45 } 46 } 47 for(j=2;j<=m;j++){ 48 for(i=j;i<=n;i++){ 49 dp[j][i]=INF; 50 for(k=j-1;k<=i-1;k++){ 51 dp[j][i]=min(dp[j][i],dp[j-1][k]+w[k][i]); 52 /* 53 if(t==0){ 54 printf("i=%d j=%d k=%d dp[j-1][k]=%d w(k,i)=%d ",i,j,k,dp[j-1][k],w[k][i]); 55 } 56 */ 57 58 } 59 60 } 61 } 62 /* 63 printf(" "); 64 for(j=1;j<=m;j++){ 65 for(i=1;i<=n;i++){ 66 printf("%3d",dp[j][i]); 67 } 68 printf(" "); 69 } 70 printf(" "); 71 */ 72 for(i=m;i<=n;i++){ 73 tmp=dp[m][i]; 74 // printf("%d ",tmp); 75 for(j=i+1;j<=n;j++){ 76 tmp+=a[j]-a[i]; 77 } 78 ans=min(ans,tmp); 79 } 80 // printf(" "); 81 printf("Chain %d Total distance sum = %d ",++c,ans); 82 } 83 return 0; 84 }