贪婪算法和动态规划

题目如下:

很久很久以前,有一位国王拥有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人0000400400400400400400
500kg黄金/5人0000500500500500500900
200kg黄金/3人00200200500500500700700900
300kg黄金/4人00200300500500500700800900
350kg黄金/3人00350350500500500850850900

 时间复杂度变成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_<int>(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");
}

输出结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值