zcmu 2165 黄金矿工(分组背包)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/81331541

分组背包:

分组背包,由基础背包演化而来的一种情况。
具体问题是这样的。具体问题是这样的。一个容量为V的背包,还有若干组物品,每组包含若干物品,这些物品各不相同,而且体积w和价值p各不相同。组内的物品相冲突。求出能在不超过V的情况下尽可能的使价值最大。
乍一看好像很难的样子,其实仔细想想很简单,这种问题完全可以用01背包解决。 对于分组背包,可以这样想:虽然分成很多组,但只能选一个,或者不选,这和01背包是一样的,也就是说,对于01背包里每一个独一无二的物品,对应的分组背包就是每一组中选择一个物品,这样来看,完全就是01背包问题。

一维的状态转移方程是:

for 所有的组k
    for v=V..0
        for 所有的i属于组k
           dp[v]=max{dp[v],dp[v-c[i]]+w[i]}
知道了分组背包,这题就很好解决了,把同一条线上的金矿当成一组,然后套模板就行了

具体代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
	double jd;
	int w;
	int v;
	int dis;
}k[1000];
bool cmp(node a, node b)
{
	if (a.jd == b.jd)
		return a.dis < b.dis;
	else
		return a.jd < b.jd;
}
int mk[1000];
int dp[40010];
int main()
{
	int n, t;
	while (cin >> n >> t)
	{
		memset(mk, 0, sizeof(mk));
		memset(k, 0, sizeof(k));
		memset(dp, 0, sizeof(dp));
		for (int i = 1; i <= n; i++)
		{
			int x, y,w,v;
			cin >> x >> y >> w >>v;
			k[i].w = w;
			k[i].v = v;
			k[i].jd = (double)(x) / (double)y;
			k[i].dis = x * x + y * y;
		}
		sort(k+1, k + n+1, cmp);
		int xb = 1;
		mk[1] = 1;//学到了,学到了,判断集合原来还能这么玩
		for (int i = 2; i <= n; i++)
		{
			if (k[i].jd == k[i - 1].jd)
			{
				mk[i] = xb;
				k[i].v += k[i - 1].v;//累加之前相同角度的金矿作为整体进行考虑
				k[i].w += k[i - 1].w;
			}
			else
			{
				mk[i] = ++xb;
			}
		}
		int i, j, z,zs=1;//zs代表每组金矿的起始下标
		for (i = 1; i <= xb; i++)//总的金矿组数
		{
			for (j =t; j>=1; j--)//背包当前容量
			{
				z = zs;
				for (; mk[z] == i;z++)//每组金矿中选一个(或者一个都不选)
				{
					if (j >= k[z].w)
					{
						dp[j] = max(dp[j], dp[j - k[z].w] + k[z].v);
					}
				}
				
			}
			zs = z;
		}
		/*for (int i = 1; i <= t; i++)
			cout << dp[i] << " ";
		cout << endl;*/
		cout << dp[t]<< endl;
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39562952/article/details/81331541