ACM PKU 1160 Post Office http://acm.pku.edu.cn/JudgeOnline/problem?id=1160
来之不易呀!!!
用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)
#include <iostream> using namespace std; const int MAX = 3000000; long cost[301][301]; long opt[301][301]; int dis[301]; int main () { int v, p_o ; int i = 1, j , k ; //memset (cost,0,sizeof(cost)); cin >> v >> p_o; for (i = 1; i <= v; i++ ) cin >> dis[i]; for (i = 1 ; i <= v ; i++) for (j = i; j <= v ; j++) { cost[i][j] = 0; int mid = (i + j)/2; for (k = mid + 1; k <= j; k++) { cost[i][j] += dis[k] - dis[mid] ; } for (k = i ; k <= mid ; k++) { cost[i][j] += dis[mid] - dis[k] ; } } for (i = 0 ; i <= p_o; i++) for (j = 0; j <= v ; j++) { opt[i][j] = MAX; } 重点看看这里: opt[0][0] = 0; for (i = 0 ; i <= p_o; i++) for (j = 0; j <= v ; j++) { for (k = 1; k + j <= v; 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]; } } cout<<opt[p_o][v]<<endl; return 0; }