POJ1160 Post Office
原题传送:http://poj.org/problem?id=1160
动态规划。
用dp[i][j]记录把前i个邮局建到前j个村庄中的最优解,用cost[i][j]记录所有在i到j村庄中,建1个邮局的最小代价。显然邮局应该设到中点。让前i个邮局覆盖前j个村庄,第i+1个邮局覆盖第j+1至j+k个村庄(j+k<=n),则状态转移方程为dp[i+1][j+k]=min{dp[i][j]+cost[j+1][j+k];}(k+j<=n)
cost数组存放从i到j中有一个邮局的最小代价,显然该邮局应该放在中间。
dp[i][j]表示前i个邮局覆盖前j个村庄的最小代价,对于i=1来说,dp[i][j]=cost[i][j],让前2个邮局覆盖前j个村庄,也就是i=2的情况,可能是一下情况的最优解:第一个邮局覆盖第一个村庄,第二个村庄覆盖2~j个村庄,或者第一个邮局覆盖第1~2个村庄,第二个村庄覆盖3~j个村庄,第一个邮局覆盖第1~3个村庄,第二个村庄覆盖4~j个村庄,等等等等。
这种题目乍一看很难想,但是如果锁定是动态规划题,那么思想就是自底向上的一种规划(这道题是对放置的警察局个数从1~p枚举)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #define N 305 4 #define INF 300010 5 6 int d[N], cost[N][N], dp[N][N]; 7 int p, v; 8 9 inline int min(int x, int y){return x < y ? x : y;} 10 int solve() 11 { 12 int i, j, k; 13 for(i = 0; i <= p; i ++) 14 for(j = 0; j <= v; j ++) 15 dp[i][j] = INF; 16 for(i = 1; i <= v; i ++) 17 dp[1][i] = cost[1][i]; 18 for(i = 1; i <= p; i ++) 19 for(j = 0; j <= v; j ++) 20 for(k = 1; j + k <= v; k ++) 21 dp[i + 1][j + k] = min(dp[i + 1][j + k], dp[i][j] + cost[j + 1][j + k]); 22 return dp[p][v]; 23 } 24 25 void init_cost() 26 { 27 int i, j, k, mid; 28 for(i = 1; i <= v; i ++) 29 { 30 for(j = i; j <= v; j ++) 31 { 32 cost[i][j] = 0; 33 mid = (i + j) >> 1; 34 for(k = i; k <= j; k ++) 35 cost[i][j] += (d[mid] - d[k]) >= 0 ? d[mid] - d[k] : d[k] - d[mid]; 36 } 37 } 38 } 39 40 int main() 41 { 42 int i; 43 while(scanf("%d%d", &v, &p) != EOF) 44 { 45 for(i = 1; i <= v; i ++) 46 scanf("%d", &d[i]); 47 init_cost(); 48 printf("%d\n", solve()); 49 } 50 return 0; 51 }