贪婪算法和动态规划

题目如下:

很久很久以前,有一位国王拥有5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人人数也不同。

如果参与挖掘的工人总数是10,每座金矿要么全挖,要么不挖,要得到尽可能多的金矿。

①200kg / 3人

②300kg / 4人

③350kg / 3人

④400kg / 5人

⑤500kg / 5人

 

贪婪算法:

对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

针对性价比:

①350kg / 3人 ,人均产量 116.6kg

②500kg / 5人 ,人均产量 100kg

③400kg / 5人 , 人均产量 80kg

④300kg / 4人 , 人均产量 75kg

⑤200kg / 3人 , 人均产量 66.6kg

结果选择前两名 850kg / 8人。

结论:得到局部最优解,但不是最好答案。

 

动态规划:

把复杂的问题简化成规模较小的子问题,再从简单的子问题自底向上一步一步递推。

 

举个例子,设金矿数量为n, 工人数量为w, 所需工人数量是p[] (数组), 产量是g[] (数组)

对于本文例子:

n = 5, w = 10, p[] = {5, 5, 3, 4, 3}, g[] = {400, 500, 200, 300, 350}

简化问题成:2个子问题

①前4个金矿,用10个工人 

②前4个金矿,用7个工人 和 第5个金矿, 用3个工人

以此递推下去,显而易见时间复杂度是O(2^n),是无法接受的。。。

并且在递推过程中,分化问题会有相同(重复)情况出现。

 

优化:

根据动态规划的自底向上的特性。

  1个工人 2个工人 3个工人 4个工人 5个工人 6个工人 7个工人 8个工人 9个工人 10个工人
400kg黄金/5人 0 0 0 0 400 400 400 400 400 400
500kg黄金/5人 0 0 0 0 500 500 500 500 500 900
200kg黄金/3人 0 0 200 200 500 500 500 700 700 900
300kg黄金/4人 0 0 200 300 500 500 500 700 800 900
350kg黄金/3人 0 0 350 350 500 500 500 850 850 900

 时间复杂度变成O(n*w) 即O(5 * 10)

 

时间复杂度达到最优,降低空间复杂度。

可以发现每一行数据都是由上一行推导出来的。

例如:4个金矿、9个工人的最优结果是由3个金矿、9个工人 和 3个金矿、5个工人结果推导。

贴出代码:

int getBestGold(int n, int w, int p[], int g[])
{
	int *results = new int[w+1];
	memset(results, 0, 4 * (w + 1));
	for(int i = 1; i <= n; i++)
	{
		for(int j = w; j >= i; j--)
		{
			if(j >= p[i-1])
			{
				results[j] = max_(results[j],
					results[j - p[i-1]] + g[i - 1]);
			}
		}
	}
	cout << "result >> ";
	for(int i = 1; i <= w; i++)
	{
		cout << results[i] << " ";
	}
	cout << endl;
	return results[w];
}
void main()
{

	int w = 10;
	int n = 5;
	int p[] = {5, 5, 3, 4, 3};
	int g[] = {400, 500, 200, 300, 350};
	cout << "gold max >> " << getBestGold(n, w, p, g);
	system("pause");
}

输出结果:

你可能感兴趣的:(c++学习之路)