DP动态规划--乡村邮局问题-Post Office(POJ-1160)

DP–乡村邮局问题-Post Office
原题点这里
题目

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

题目解析
1.题目意思:
在一个水平坐标轴上有V个村子,每个村子的位置上都可以建一座邮局,一共有P个邮局,问V个村子P个邮局的建造方案中,村子到邮局的最短距离和为多少。(只要求距离,不需要把具体方案输出来)。
2.题目思路:
我们可以轻松的知道一定范围内的村子中建造一个邮局的最短距离和,那我们以此为突破口。
先确定dp[a][b]表示1到a的村子(前a个村子) 设置b个邮局的 最短距离和。然后我们知道

dp[i][j] = min(dp[i][j], dp[k][j - 1] + bdis[k + 1][i]);

循环k,即前k村设置j-1个邮局( dp[k][j - 1]),后面k+1到i的村子设置1个邮局(bdis[k + 1][i]),与原dp[i][j]比较得到最小dp[i][j].

不多说上代码与注释:

int main()
{
	int vnum, pnum;
	cin >> vnum >> pnum;
	int dp[310][40];//dp[a][b]存放 1到a的村子(前a个村子) 设置b个邮局的 最短距离和。
	int v[1000];//存放村庄位置
	int bdis[310][310];//bdis[a][b]存放从a--b的村子之间存放一个邮局的最短距离和,为最基础的距离和(basic distance),是dp循环的基础元
	for (int i = 1; i <= vnum; i++) {
		cin >> v[i];
	}
	memset(bdis, 0, sizeof(bdis));
	memset(dp, 0, sizeof(dp));//初始化dp数组为0,主要为初始化dp[a][b]中a=b的情况,即村庄数与邮局数相等,必然是距离和为0
	for (int i = 1; i <= vnum; i++)
	{
		for (int j = i + 1; j <= vnum; j++)
		{
			bdis[i][j] = bdis[i][j - 1] + v[j] - v[(i + j) / 2];//利用迭代求出bdis的值(当村庄数为偶数时,邮局设置在偏左的中心和偏右的中心并不影响最短距离,所以直接加上v[j] - v[(i + j) / 2]即可)
			if (i == 1) {
				dp[j][1] = bdis[i][j];//初始化dp[a][b]中b为1的情况,即前a个村子只有一座邮局的情况(由于是前a个村子,所以bdis[i][j]的i必须为1)
			}
		//	cout << "bdis " << bdis[i][j] << endl;
		}
	}
	for (int j = 2; j <= pnum; j++) {//j为设置多少邮局,由于j为1时前一循环已经初始化(只有一座邮局的情况),所以j从2开始(至少两座邮局)
		for (int i = j + 1; i <= vnum; i++) {//i为村子数,至少要为j,但ij相等的情况已经初始化为0,所以i从j+1开始
			dp[i][j] = 0x3f3f3f3f;
			for (int k = j - 1; k < i; k++) {//循环k,即前k村设置j-1个邮局( dp[k][j - 1]),后面k+1到i的村子设置1个邮局(bdis[k + 1][i]),与原dp[i][j]比较得到最小dp
				dp[i][j] = min(dp[i][j], dp[k][j - 1] + bdis[k + 1][i]);
			}
			
		}
	}
	cout << dp[vnum][pnum] << endl;
	return 0;
}


  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ - 3616是一个题目,题目描述如下: 给定一组区间,每个区间有一个权重,要求选择一些区间,使得这些区间的右端点都小于等于k,并且权重之和最大。请问最大的权重和是多少? 解决这个问题的思路是使用动态规划。首先,将区间按照左端点从小到大进行排序。然后,定义一个dp数组,dp[i]表示右端点小于等于i的所有区间所能得到的最大权重。 接下来,遍历每一个区间,对于每个区间i,将dp[i]初始化为区间i的权重。然后,再遍历i之前的每个区间j,如果区间j的右端点小于等于k,并且区间j的权重加上区间i的权重大于dp[i],则更新dp[i]为dp[j]加上区间i的权重。 最后,遍历整个dp数组,找到最大的权重和,即为所求的答案。 下面是具体的代码实现: ```cpp #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct interval{ int start, end, weight; }; interval intervals[10005]; int dp[10005]; int n, m, k; bool compare(interval a, interval b) { if (a.start == b.start) { return a.end < b.end; } else { return a.start < b.start; } } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp, 0, sizeof dp); for (int i = 0; i < m; i++) { scanf("%d %d %d", &intervals[i].start, &intervals[i].end, &intervals[i].weight); } sort(intervals, intervals + m, compare); for (int i = 0; i < m; i++) { dp[i] = intervals[i].weight; for (int j = 0; j < i; j++) { if (intervals[j].end <= k && dp[j] + intervals[i].weight > dp[i]) { dp[i] = dp[j] + intervals[i].weight; } } } int maxWeight = 0; for (int i = 0; i < m; i++) { maxWeight = max(maxWeight, dp[i]); } printf("%d\n", maxWeight); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值