hdu1227 dp

题意:在一条路上有 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("\nw:\n");
31         for(i=1;i<=n;i++){
32             for(j=1;j<=n;j++){
33                 printf("%3d",w[i][j]);
34             }
35             printf("\n");
36         }
37         printf("\n");
38 */
39     //    printf("min=%d\n",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\nj=%d\nk=%d\ndp[j-1][k]=%d\nw(k,i)=%d\n",i,j,k,dp[j-1][k],w[k][i]);
55                     }
56 */
57
58                 }
59
60             }
61         }
62 /*
63         printf("\n");
64         for(j=1;j<=m;j++){
65             for(i=1;i<=n;i++){
66                 printf("%3d",dp[j][i]);
67             }
68             printf("\n");
69         }
70         printf("\n");
71 */
72         for(i=m;i<=n;i++){
73             tmp=dp[m][i];
74         //    printf("%d\n",tmp);
75             for(j=i+1;j<=n;j++){
76                 tmp+=a[j]-a[i];
77             }
78             ans=min(ans,tmp);
79         }
80     //    printf("\n");
81         printf("Chain %d\nTotal distance sum = %d\n\n",++c,ans);
82     }
83     return 0;
84 }

时间: 2024-11-17 21:25:16

hdu1227 dp的相关文章

hdu1227 dp 经典

1 //Accepted 420 KB 15 ms 2 //刚开始的时候一直在想把depot放在哪个restaurant,结果一直陷在里面,不知道该怎么转移 3 //现在我们把i到j看成一段处理,就认为i到j由一个depot供应,而与其他depot没有关系,且 4 //这个depot与其他的restaurant也没有关系,那么对于i到j这一段产生的花费就可以计算出来 5 //由cost[i][j]表示,对于i到j这一段,把depot放到(i+j)/2这个restaurant上,产生的花费最少 6

DP总结 ——QPH

常见优化 单调队列 形式 dp[i]=min{f(k)} dp[i]=max{f(k)} 要求 f(k)是关于k的函数 k的范围和i有关 转移方法 维护一个单调递增(减)的队列,可以在两头弹出元素,一头压入元素. 队列中维护的是两个值.一个是位置,这和k的范围有关系,另外一个是f(k)的值,这个用来维护单调性,当然如果f(k)的值可以利用dp值在O(1)的时间内计算出来的话队列中可以只维护一个表示位置的变量. 枚举到一个i的时候,首先判断队首元素的位置是否已经不满足k的范围了,如果不满足就将队首

hdu1227 Fast Food

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1227 #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string.h> #include <string> using namespace std; const int MAXN = 200 + 1; //the

【DP|数学+预处理】POJ-1160 Post Office

Post Office Time Limit: 1000MS Memory Limit: 10000K Description There is a straight highway with villages alongside the highway. The highway is represented as an integer axis, and the position of each village is identified with a single integer coord

poj1160 dp

1 //Accepted 564 KB 63 ms 2 //和hdu1227一样 3 //dp[i][j]=min(dp[i][j],dp[k][j-1]+cost[k+1][i]) 4 //初始化条件,dp[0][0]=0; 5 //dp[i][0]=inf;i>=1; 6 #include <cstdio> 7 #include <cstring> 8 #include <iostream> 9 using namespace std; 10 const in

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

POJ - 3186 Treats for the Cows (区间DP)

题目链接:http://poj.org/problem?id=3186 题意:给定一组序列,取n次,每次可以取序列最前面的数或最后面的数,第n次出来就乘n,然后求和的最大值. 题解:用dp[i][j]表示i~j区间和的最大值,然后根据这个状态可以从删前和删后转移过来,推出状态转移方程: dp[i][j]=max(dp[i+1][j]+value[i]*k,dp[i][j-1]+value[j]*k) 1 #include <iostream> 2 #include <algorithm&

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.