Post Office POJ - 1160

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38449464/article/details/79541759

Post Office

  POJ - 1160 

There is a straight highway with villages alongside the highway. The highway is represented as an integer axis, and the position of each village is identified with a single integer coordinate. There are no two villages in the same position. The distance between two positions is the absolute value of the difference of their integer coordinates. 

Post offices will be built in some, but not necessarily all of the villages. A village and the post office in it have the same position. For building the post offices, their positions should be chosen so that the total sum of all distances between each village and its nearest post office is minimum. 

You are to write a program which, given the positions of the villages and the number of post offices, computes the least possible sum of all distances between each village and its nearest post office. 
Input
Your program is to read from standard input. The first line contains two integers: the first is the number of villages V, 1 <= V <= 300, and the second is the number of post offices P, 1 <= P <= 30, P <= V. The second line contains V integers in increasing order. These V integers are the positions of the villages. For each position X it holds that 1 <= X <= 10000.
Output
The first line contains one integer S, which is the sum of all distances between each village and its nearest post office.
Sample Input
10 5
1 2 3 6 7 9 11 22 44 50
Sample Output
9

每次做dp的时候,都觉得自己像一个弱智...

开始的时候想过先假设i个村有i个点,那么i-1的时候,就去找到距离左右两边最近的一个点然后去掉,i-2就是再剩下的再找。这种思路对于 样例里的 1 2 3就没办法定夺,没有理由让你去1 3 ,留下2。

然后发现了对于一个点的情况下,最优解肯定是在中点,而且如果是偶数,n/2 和 n/2+1 等效。于是想到先从一个点开始,然后加第二点。但是由于我假设 之前的点都是完美的,即第一个点放在2/1处,第二个点放在4/1 或者 4/3 处,所以也没用结果。

再然后想到 先对先求出只有一个邮点的所有情况。即设一个num[305][305]的数组,num[i][0]存值,num[i][j],就是邮点在j,然后每个点到j点的距离。这种情况下,只要举例出每个邮点管理的范围,就可以直接加起来。例如 123 由2管理,679 11由7管理,22、44、50分别管理自己。虽然感觉上可以实现,但是似乎要枚举管理范围,而且实现也有些麻烦,又放弃了。


最后实在受不了看了题解……虽然知道是dp,但是感觉自己完全没往那方向走,状态方程 子问题 一点都找不到


题解: 首先设置了dp[i][j] 为对前i个村有j个邮点 的min值

            那么dp[i][j] ,对于新加入的村,我们必须分出一个邮点照顾它,并且邮点分出后照顾范围是不确定的,需要枚举取最小。而分出邮点之后dp[i][j-1] 对于j-1层的所有数据之前都是求过的,所以可以推出式子 dp[i][j] = dp[k][j-1] + cost(k+1,i)     j-1<=k<=i -1  cost(n,m) 是求对n,m村中,插入一个邮点 所得到的最小值

            由于j-1层 的数据已知,所以dp[k][j-1] 所表示的前k个村j-1个邮点 的最小值可以直接用 ,后面cost(k+1,i) 指在第k+1个村 和 第i个村之间插入一个邮点 得到的最小值

代码:

#include<iostream>
#include<cstdio>
#include<memory.h>
#include<algorithm>
using namespace std;
int dp[305][305];
int cost(int n,int m){
	int a =(n+m)/2,sum=0,tmp;
	for(int i=n;i<=m;i++){
		tmp = dp[i][0] - dp[a][0];
		if(tmp < 0) tmp = -tmp;
		sum+=tmp;
	}
	return sum;
} 
int main(){
	int v,p;
	cin>>v>>p;
	memset(dp,-1,sizeof(int)*305*305);
	for(int i=1;i<=v;i++){
		cin>>dp[i][0];// 0层表示的是值  
		if(i>=2) dp[i][1] = cost(1,i);//把第一层数据 推出来 
		else dp[1][1] = 0;
	}
	for(int j=2;j<=p;j++){//对第j个节点 dp 
		dp[j][j] = 0;
		for(int i=j+1;i<=v;i++){//从j+1开始,因为之前都是0 
			int in = 99999999,t;
			for(int k=j-1;k<=i-1;k++){// k即枚举的管理范围 
				t = dp[k][j-1] + cost(k+1,i);  //取 min 
				if(t < in) in = t;;
			}		
			dp[i][j] = in;
	//		cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
		}
	}
	cout<<dp[v][p]<<endl;
}







猜你喜欢

转载自blog.csdn.net/qq_38449464/article/details/79541759