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枚举)。

View Code
 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 }
posted @ 2012-09-10 12:40  芒果布丁  阅读(264)  评论(0编辑  收藏  举报