poj 1160 动态规划
题意:n (n<=300)个村庄,要建设m (m<=30)个邮局,每个村庄使用最近的邮局,问总距离最小是多少?
分析:
最初的想法:dp(i, j)表示前j个村庄建设i个邮局,并且第i个邮局建设在第j个村庄的最小距离,
则dp(i, j) = min ( dp(i-1,k) + dist(k,j) )。(i-1<=k<j, dist(k,j)为在村庄k和村庄j建设邮局,k和j之间的村庄到他们的最小距离)。
由于n>=m,即最优解一定建设了m个邮局,第m个邮局可能建设在第k(m<=k<=n)个村庄,k+1~n的村庄只能到第k个村庄去,
所以答案为min ( dp(m,k)+D(k) ) (m<=k<=n, D(k)为k+1~n的村庄到k的距离和)。
const int N = 305, M = 33; int n, m; int dp[M][N], a[N]; int dist[N][N]; int d(int i, int j){//在i和j建造邮局,i j之间的村庄到他们的距离 if(dist[i][j]) return dist[i][j]; if(j-i<=1) return 0; int t = 0, mid = (a[i]+a[j])/2; FOE(k, i+1, j-1){ if(a[k]<=mid) t += a[k]-a[i]; else t += a[j]-a[k]; } dist[i][j] = t; return t; } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif scanf("%d%d", &n, &m); FOE(i, 1, n) scanf("%d", &a[i]); a[n+1] = 99999999; FOE(j, 2, n) { dp[1][j] = dp[1][j-1]+(j-1)*(a[j]-a[j-1]); //cout<<1<<' '<<j<<' '<<dp[1][j]<<endl; int t = min(j, m); FOE(i, 2, t){ dp[i][j] = -1; FOR(k, i-1, j){ checkmin(dp[i][j], dp[i-1][k]+d(k, j)); } //cout<<i<<' '<<j<<' '<<dp[i][j]<<endl; } } int ans = -1; FOE(j, m, n) checkmin(ans, dp[m][j]+d(j,n+1)); printf("%d\n", ans); return 0; }