HDU4341-Gold miner-分组DP

时间:2023-03-10 03:44:14
HDU4341-Gold miner-分组DP

模拟黄金矿工这个游戏,给出每一个金子的位置和所需时间,计算在给定时间内最大收益。

刚看这道题以为金子的位置没什么用,直接DP就行,WA了一发终于明白如果金子和人共线的话只能按顺序抓。

这就是需要考虑先后关系问题。看了背包⑨讲之后以为是“有依赖关系的背包”,感觉解决方案很不明显,想不出来做法。

后来想到,可以把共线的金子按1,1+2,1+2+3。。。变成若干个,然后共线的金子组成一组。

显然这个问题就变成了在组内互斥的情况下的分组DP,背包⑨讲已经给出了伪代码。

预处理的时候使用了优先队列,map,乱搞了一下就好了。。。//好不容易自己写出来了一道不太水的题。。。

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <map> using namespace std; const int maxn = +; struct node
{
int x,y;
int w,v;
node(){x=;y=;w=;v=;}
node(int x,int y) {w=x;v=y;}
bool operator < (const node &b) const
{
return x*x+y*y > b.x*x+b.y*y;
} }gold[maxn]; struct item
{
int w,v;
item(){w=;v=;}
item(int a,int b){w=a;v=b;}
}; int x[maxn],y[maxn],w[maxn],v[maxn],dp[];
int N,T;
vector <item> itm[maxn]; int main()
{
int cas = ;
while(~scanf("%d%d",&N,&T))
{
map<pair<int,int> , int > mp;
priority_queue<node> pq[maxn];
int cnt_group = ;
for(int i=;i<maxn;i++) itm[i].clear(); for(int i=,x,y;i<N;i++)
{
scanf("%d%d%d%d",&gold[i].x,&gold[i].y,&gold[i].w,&gold[i].v);
x = gold[i].x;y = gold[i].y; if(mp.count(pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y)) ))
{
pq[mp[pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y))]].push(gold[i]);
}
else
{
mp[pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y))]=cnt_group++;
pq[mp[pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y))]].push(gold[i]);
}
} map<pair<int,int>,int >::iterator it;
node cur;
for(int i=;i<cnt_group;i++)
{
cur = node(,);
while(!pq[i].empty())
{
cur.w += pq[i].top().w;
cur.v += pq[i].top().v;
pq[i].pop();
itm[i].push_back(item(cur.w,cur.v));
//printf("grp:%d w:%d v:%d\n",i,cur.w,cur.v);
}
}
memset(dp,,sizeof dp); for(int gp=;gp<cnt_group;gp++)
{
int n = itm[gp].size(); for(int t=T;t>=;t--)
{
for(int i=;i<n;i++) if(t>=itm[gp][i].w)
{
//printf("t:%d w:%d\n",t,itm[gp][i].w);
dp[t] = max(dp[t],dp[t-itm[gp][i].w] + itm[gp][i].v);
}
}
//for(int i=0;i<T;i++)
//printf("%d ",dp[i]);
//printf("\n");
} printf("Case %d: %d\n",cas++,dp[T]);
}
}