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;
}