题目:
有一条公路经过V个村庄,每一个村庄都处在整数的坐标点上(这里假设公路为数轴)。规划在这条公路上建立P个邮局,每一个邮局都要建在某个村庄上,要求让不同村庄的人到邮局要走的总路程最小。
分析:
用动态规划的办法,先把输入的村庄排序,然后计算只有一个邮局的情况,然后再根据已有的信息,计算p(p>=2)个邮局时的选址分布,其中p从小到大计算。
class addr_info
{
public:
int dis;
int behind;
addr_info() :dis(0), behind(0){}
};
class PostSite
{
public:
vector<vector<int>> postsite;//只有一个邮局时,两个村庄之间的选址位置
vector<vector<int>> distance;//两点之间只有一个邮局时,所有村庄要走的距离之和
vector<vector<addr_info>> totaldis;//
int size;//村庄的数目
//假设输入的村庄坐标是大于等于零的整数
vector<int> main_function(vector<int> villages, int num_of_postoffices)
{
vector<int> res;
if (villages.empty() || num_of_postoffices == 0)
return res;
size = villages.size();
if (num_of_postoffices >= size)
return villages;
//排序,不可以忘记这一步
sort(villages.begin(), villages.end());
//初始化postsite
postsite = vector<vector<int>>(size, vector<int>(size,0));
for (int l = 0; l < size; ++l)
{
for (int r = l; r < size; ++r)
{
int mid = l + (r - l) / 2;
postsite[l][r] = villages[mid];
}
}
//初始化distance
distance = vector<vector<int>>(size, vector<int>(size, 0));
for (int l = 0; l < size; ++l)
{
for (int r = l+1; r < size; ++r)
{
int pos = postsite[l][r],sum=0;
for (int k = l; k <= r; ++k)
{
if (villages[k] < pos)
sum += pos - villages[k];
else
sum += villages[k] - pos;
}
distance[l][r] = sum;
}
}
//计算totaldis
totaldis = vector<vector<addr_info>>(size, vector<addr_info>(num_of_postoffices+1));
//只有一个邮局的情况
for (int i = 0; i < size; ++i)
{
totaldis[i][1].dis = distance[i][size - 1];
//totaldis[i][1].behind = i;
}
//有2个或2个以上邮局的情况
for (int p = 2; p <= num_of_postoffices; ++p)
{
for (int i = 0; i <= size - p; ++i)
{
totaldis[i][p].dis = 0x7fffffff;
totaldis[i][p].behind = 0;
//把[i,j]作为第一个分区
for (int j = i; j+1 <= size - (p-1); ++j)
{
int temp = distance[i][j] + totaldis[j+1][p - 1].dis;
if (temp < totaldis[i][p].dis)
{
totaldis[i][p].dis = temp;
totaldis[i][p].behind = j + 1;//behind记录第二个分区的开始位置
}
}
}
}
//把结果输出到res
output(0, num_of_postoffices, res);
return res;
}
void output(int left, int p, vector<int> &res)
{
if (p == 1)
{
res.push_back(postsite[left][size-1]);
}
else
{
int right = totaldis[left][p].behind;
res.push_back(postsite[left][right - 1]);
output(right, p - 1, res);
}
}
};
main函数中这样调用:
PostSite a;
//vector<int> v = { 1, 4, 7, 19, 70, 89, 105, 204, 18, 40 };
vector<int> v = { 1,2,3,4,5,6,7 };
auto r=a.main_function(v, 3);
for (auto &i : r)
cout << i << " ";
cout << endl;