【例9.16】分组背包 代码

分组背包

思路一

很简单的题目。不过是在01背包上增加约束而已。
思路:对于物品i分两种情况,放或者不放,计算那种情况可以获得的背包总价值最大,就是答案了。
总结下自己的错误点:放物品前需要判断:1.该组别是否已经放过 2.放入该物品是否会背包溢出!!!

#include
#define UP(i,x,y) for(int i=x; i<=y; i++)
#define LEN 999
using namespace std;

int w[LEN]; // 重量 
int c[LEN]; // 价值 
int p[LEN];	 // 第i号物品的组别 
int bookGroup[100]={0}; // 第i组是否已经选取 
int v,n,t; 
vector<int> arr;
int k ;

/*
	i: 第i个物品  
	syM: 剩余的重量 
*/ 
int dfs(int i, int syW)
{
	int temp1 = 0;
	int temp2 = 0;
	if(i == n + 1)
	{
		return 0;
	}
	
	/* 放入i物品获得的背包总最大价值 temp1 */ 
	if(bookGroup[p[i]] == 0)
	{
		if(syW - w[i] >= 0)
		{
			bookGroup[p[i]] = 1;
			temp1 = c[i] + dfs(i+1, syW - w[i]);
			bookGroup[p[i]] = 0;
		}
	}
	
	/* 不放入i物品获得的背包总最大价值 temp2 */ 
	temp2 = dfs(i+1, syW);
	return max(temp1, temp2);
}

int main()
{
	cin>>v>>n>>t;
	UP(i, 1, n)
	{
		cin>>w[i];
		cin>>c[i];
		cin>>p[i];
	}
	cout<<dfs(1, v);
	return 0;
}

思路二

将每个组别看成一个超大的物品,这个物品里面还有很多小物品。这样的好处是后面记忆化方便点。

#include
#define UP(i,x,y) for(int i=x; i<=y; i++)
#define LEN 9999
using namespace std;

int w[LEN]; // 重量 
int c[LEN]; // 价值 
int p[LEN];	 // 第i号物品的组别 
vector< vector<int> > g(LEN); // 组 
//int bookGroup[100]={0}; // 第i组是否已经选取 
int dp[LEN][LEN] = {0}; 
int v, n, t; 

/*
	i: 第i组 
	syM: 剩余的重量 
	return 还剩syM空间,放入i~t组  能获得的最大价值是多少 
*/ 
int dfs(int i, int syW)
{
	int temp1 = 0;
	int temp2 = 0;
	if(i == t + 1)
	{
		return 0;
	}
	
	if(dp[i][syW] != 0)
	{
		return dp[i][syW];
	}
	
	/* 不放第i组的物品 */ 
	temp1 = dfs(i+1, syW);
	
	/* 放第i组的物品 */
	/* 尝试放第i组的第j个物品 */ 
	for(vector<int>::iterator j = g[i].begin(); j != g[i].end(); ++j)
	{ 
		/* 判断是否溢出背包空间 */
		if(syW - w[*j] >= 0)
		{
			int tp = dfs(i+1, syW - w[*j]) + c[*j];
			temp2 = max(tp, temp2);
		}
	}
	return dp[i][syW] = max(temp1, temp2);
}

int main()
{
	cin>>v>>n>>t;
	UP(i, 1, n)
	{
		cin>>w[i];
		cin>>c[i];
		cin>>p[i];

		g[p[i]].push_back(i);
	}
	cout<<dfs(1, v);
	return 0;
}

你可能感兴趣的:(noip算法题)