http://acm.pku.edu.cn/JudgeOnline/problem?id=1160
题目给出m个村庄及其距离,给出n个邮局,要求怎么建n个邮局使代价最小。
思路:用opt[i][j]记录把前i个邮局建到前j个村庄中的最优解,用cost[i][j]记录所有在i到j村庄中,建1个邮局的最小代价。显然邮局应该设到中点。让前i个邮局覆盖前j个村庄,第i+1个邮局覆盖第j+1至j+k个村庄(j+k<=n),则状态转移方程为
opt[i+1][j+k]=min{opt[i][j]+cost[j+1][j+k];} (k+j<=n)
Cost数组存放从i到j中有一个邮局的最小代价,显然该邮局应该放在中间,构造cost的代码和结果如下:
for(i=1;i<=m;i++)
for(j=i;j<=m;j++)
{
cost[i][j] = 0;
mid = (i+j)/2;
for(k=i;k<=j;k++)
cost[i][j]+=(distance[mid]-distance[k])>=0 ?
distance[mid]-distance[k]:distance[k]-distance[mid];
}
Cost[i][j] | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
1 | 0 | 1 | 2 | 6 | 10 | 16 | 21 | 37 | 74 | 117 |
2 |
| 0 | 1 | 4 | 8 | 11 | 16 | 31 | 68 | 109 |
3 |
|
| 0 | 3 | 4 | 7 | 11 | 26 | 61 | 102 |
4 |
|
|
| 0 | 1 | 3 | 7 | 20 | 55 | 94 |
5 |
|
|
|
| 0 | 2 | 4 | 17 | 50 | 89 |
6 |
|
|
|
|
| 0 | 2 | 13 | 46 | 74 |
7 |
|
|
|
|
|
| 0 | 11 | 33 | 61 |
8 |
|
|
|
|
|
|
| 0 | 22 | 28 |
9 |
|
|
|
|
|
|
|
| 0 | 6 |
10 |
|
|
|
|
|
|
|
|
| 0 |
Opt[i][j] 表示前i个邮局覆盖前j个村庄的最小代价,对于i=1来说,opt[i][j] = cost[i][j],让前2个邮局覆盖前j个村庄,也就是i=2的情况,可能是一下情况的最优解:第一个邮局覆盖第一个村庄,第二个村庄覆盖2-j个村庄,或者第一个邮局覆盖第1-2个村庄,第二个村庄覆盖3-j个村庄,第一个邮局覆盖第1-3个村庄,第二个村庄覆盖4-j个村庄,等等等等。该部分的代码如下:
for(i=0;i<=n;i++)
for(j=0;j<=m;j++)
if(opt[i][j]<3000000)
{
for(k=1;j+k<=m;k++)
{
if(opt[i+1][j+k]>opt[i][j]+cost[j+1][j+k])
{
opt[i+1][j+k] = opt[i][j]+cost[j+1][j+k];
}
}
}
Opt[i][j] | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
0 | 0 |
|
|
|
|
|
|
|
|
|
|
1 |
| 0 | 1 | 2 | 6 | 10 | 16 | 21 | 37 | 74 | 117 |
2 |
|
| 0 | 1 | 4 | 8->5 | 11->8 | 16->12 | 31->27 | 68->62 | 109->103 |
3 |
|
|
|
|
|
|
|
|
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|
|
|
|
带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得