算法九讲实践(附C++代码,有详细注释)

经典的算法九讲在此不做介绍,详细可参照https://www.cnblogs.com/jbelial/articles/2116074.html。
下面,主要讲我在看此博客时的经历和详细代码实现:
1.01背包问题
01背包问题,N个物品,费用costs[i],价值values[i],最多花费V,每个物体最多可选一次,求最大价值
故可用f[i][v]表示处理前i个物品消费恰好为v的价值
则状态转移方程为:f[i][v]=max{f[i-1][v-costs[i]]+values[i],f[i-1][v]};
(1)时间复杂度O(VN),空间复杂度O(VN)的实现,,此法可顺便将买下哪些物品求出,方法:

vector<int> getMaxPathOne(vector<int>&costs, vector<int>& values, int V)
{
	vector<int> path;
	vector<int> tmpRes(V+1,0);
	vector<vector<int>> results(costs.size(),tmpRes);

	//只考虑第一个物品时,只有当消费恰好为costs[0]时,才可将该物品买下,否则消费不能满足“恰好”两字
	results[0][costs[0]] = values[0];

	for (int i=1;i<costs.size();++i)
	{
		for (int j=0;j<=V;++j)
		{
			if (j>=costs[i])//如果消费恰好为j时,买得起第i个物体
			{
 				results[i][j] = max(results[i - 1][j - costs[i]] + values[i], results[i - 1][j]);
			}
			else//如果买不起
			{
				results[i][j] = results[i - 1][j];
			}
		}
		
	}

	int value = 0;
	for (int i=1;i<=V;++i)//找出对所有物体进行处理时,价值最大时的消费是多少
	{
		if (results[costs.size()-1][i]>results[costs.size()-1][value])
		{
			value = i;
		}
	}
	//接下来找出要放哪些物体
	int i = costs.size() - 1, v = value;
	while (i>0)
	{
		if (results[i][v]!=results[i-1][v])//如果消费为v时,处理前i个物体与处理前i-1个物体的最大价值相同,
											//则第i个物品是不被放入的;反之,则放入
		{
			path.push_back(costs[i]);
			v = v - costs[i];
		}
		--i;
	}
	if (v>=costs[0])//对于第1个物体,看剩下的钱能不能买第一件,若够,就买
	{
		path.push_back(costs[0]);
	}
	return path;
}

(2)算法九讲中对01背包的空间优化方法,时间复杂度O(V*N),空间复杂度O(N):
f[v]表示花费最大为v时的最大价值,则i从低处循环时可得f[v]=max{f[v],f[v-costs[i]]+values[i]},max中的
f[v]代表处理前i-1个物体,消费不超过v时的最大价值

int getMaxValueOne(vector<int>& costs, vector<int>& values,int V)
{
	vector<int> results(V+1,0);//花费最大为0~V时的价值
	for (int i=0;i<=V;++i)//只考虑第一个物品时,允许花费范围为0~V
	{
		if (i>=costs[0])
		{ 
			results[i] = values[0];
		}
	}
	for (int i=1;i<costs.size();++i)//恰好处理前i个物品时,允许花费范围为0~V
	{
		for (int j=V;j>=costs[i];--j) //保证第i次循环结束后f[v]中表示的就是我们定义的状态f[v]
		{
			//前i个物品消费恰好为j的价值=max(不买第i个物品消费恰好为j的价值,买第i个物品消费恰好为j的价值)
			results[j] = max(results[j],results[j-costs[i]]+values[i]);//因为i从小循环上来,故max中的results[j]即为result[j-1]
		}
	}
	return results[V];
}

2.完全背包问题
N个物品,费用costs[i],价值values[i],最多花费V,每个物体可选无数次,求最大价值。
f[i][v]表示消费恰好为v,在处理第i个物体时的最大价值,f[i][v]=max{f[i-1][v],f[i][v-costs[i]]+values[i]};
(1)时间复杂度O(VN),空间复杂度O(VN)的实现,,此法可顺便将买下哪些物品求出,方法:

vector<int> getMaxPathAbso(vector<int>&costs, vector<int>&values, int V)
{
	vector<int> tmpRes(V+1,0);
	vector<vector<int>> results(costs.size(),tmpRes);
	for (int i = 1; costs[0]*i <= V; ++i)//只考虑第一个物品时,消费恰好为costs[0]的整数倍时,才可进行消费
	{
		results[0][costs[0] * i] = values[0] * i;
	}

	for (int i=1;i<costs.size();++i)
	{
		for (int j=0;j<=V;++j)
		{
			if (j>=costs[i])
			{
				results[i][j] = max(results[i-1][j],results[i][j-costs[i]]+values[i]);
			}
			else
			{
				results[i][j] =results[i-1][j];
			}
		}
	}
	int size = costs.size();
	int maxCost = 0;//处理前i个物体时,价值最大时的消费
	for (int i=0;i<=V;++i)
	{
		if (results[size-1][i]>results[size-1][maxCost])
		{
			maxCost = i;
		}
	}

	
	vector<int> path;
	//接下来找出要放哪些物体
	int i = costs.size() - 1, v = maxCost;
	while (i > 0)
	{
		if (results[i][v] != results[i - 1][v])//如果消费为v时,处理前i个物体与处理前i-1个物体的最大价值相同,
											//则第i个物品是不被放入的;反之,则放入
		{
			path.push_back(costs[i]);
			v = v - costs[i];
			++i;
		}
		--i;
	}
	if (v % costs[0]==0)//对于第1个物体,看剩下的钱能不能买第一件,若够,就买
	{
		int k = v / costs[0];
		while (k>0)
		{
			path.push_back(costs[0]);
			--k;
		}
	}
	return path;
}

(2)优化方法,时间复杂度O(NV),空间复杂度O(V)的方法:

int getMaxValueAbso(vector<int>&costs, vector<int>&values, int V)
{
	vector<int> results(V+1,0);
	for (int i = 0; i <= V; ++i)//只考虑第一个物品时,允许花费范围为0~V
	{
		results[i] = values[0]*(i/costs[0]);
	}
	for (int i=1;i<costs.size();++i)
	{
		for (int j=0;j<=V;++j)
		{
			if (j>=costs[i])
			{
				results[j] = max(results[j],results[j-costs[i]]+values[i]);
			}
		}
	}
	return results[V];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值