poj 1160 Post Office(DP)

首先要知道一个定理就是在一个区间内如果要设置一个邮局的话,最优位置一定是最中间的村子,而且如果村子数是偶数的话,中间的两个点是等价的。

知道了这个之后,就可以N^2处理出来任一一个区间中只设置一个邮局的最小距离和。cost[i][j]表示区间村子i到村子j。


dp[i][j]表示前i个村庄中设置j个邮局之后的最小距离和。

那么转移就是dp[i][j]=min(dp[i-1][k]+cost[k+1][j]) (枚举k且k<j)


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int V,P;
int Abs(int n){
	return n>0?n:(-n);
}
int dp[40][305];
int p[305];
int cost[305][305];
int Get(int i,int j){
    int mid=(i+j)/2;
    int sum=0;

    for(int k=i;k<=j;k++){
		sum+=Abs(p[k]-p[mid]);
    }
    return sum;
}
int main(){

	while(~scanf("%d%d",&V,&P)){
		memset(dp,0x3f,sizeof(dp));
		for(int i=1;i<=V;i++){
			scanf("%d",&p[i]);
		}
		for(int i=1;i<=V;i++){
			for(int j=i;j<=V;j++){
				cost[i][j]=Get(i,j);
				//cout<<cost[i][j]<<endl;
			}
		}
		for(int i=1;i<=V;i++){
			dp[1][i]=cost[1][i];
		}
		for(int i=2;i<=P;i++){
			for(int j=i;j<=V;j++){
				for(int k=1;k<j;k++){
					dp[i][j]=min(dp[i][j],dp[i-1][k]+cost[k+1][j]);
				}
			}
		}
		cout<<dp[P][V]<<endl;
		
	}
	return 0;
}


你可能感兴趣的:(poj 1160 Post Office(DP))