【动态规划】邮局选址问题

题目:

有一条公路经过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;

    原文作者:动态规划
    原文地址: https://blog.csdn.net/bupt8846/article/details/46291947
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞