分组背包:
分组背包,由基础背包演化而来的一种情况。
具体问题是这样的。具体问题是这样的。一个容量为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;
}