您的位置:首页 > 其它

Magina HDU - 3810 dfs+01背包队列模拟

2017-11-22 21:11 381 查看
Magina, also known as Anti-Mage, is a very cool hero in DotA (Defense of the Ancient).



If you have no idea of him, here is some brief introduction of his legendary antecedents:

Twin sons to the great Prophet, Terrorblade and Magina were blessed with divine powers: Terrorblade granted with an unnatural affinity with life forces; Magina gifted with energy manipulation. Magina's eventual overexposure to the magic gradually augmented
his elemental resistances and bestowed him the unique ability to move faster than light itself. Now, broken by Terrorblade's fall to the dark side, Magina answers the Sentinel's call in a desperate bid to redeem his brother. Every bitter strike turns the Scourge's
evil essences upon themselves, culminating in a finale that forces his enemy to awaken to the void within and spontaneously implode.

Magina has a very IMBA (imbalanced) skill – Blink, yes, move from one place to another place in a wink. Our problem begins at there.

As a formidable hero in the later stage, Magina always farm with the wild monsters for a long time. To make the farming more efficient, Magina use Blink frequently to jump here and there. Here we assume Blink skill has no CD, that is, we can use this skill
at any time we want.

There are N spots of the wild monsters, and Magina can choose any one to begin. For every spots, Magina may use Ti time to kill the monsters and gain Gi units money, or he choose blink to other spots, which is known to our brilliant Magina. If the monsters
in a spot were killed, it won’t appear any more.

Now Magina want to get M units money to but some excellent equipment, say Battle Fury for example. As a hero to save the world, there is no much time left for Magina, he wonders the minimum time for him to gain at least M units money.

Input The first line contains a single integer T, indicating the number of test cases.

Each test case begins with two integers N, M. Their meanings are the same as the description.

Then N blocks follow, each one describes a spot of wild monsters.

The first line of each block is there integers Ti, Gi and Ki. Ti is the time, Gi is the units of money, Ki is the number of spots Magina can blink to from here.

Then Ki integer Cij follow, indicating the spots’ ID Magina can blink to. You may assume no ID would appear twice.

The spots are described with ID increasing from 1 to N. Input ensure if you can blink from i to j, you can also blink from j to i.

Technical Specification

1. 1 <= T <= 50

2. 1 <= N <= 50

3. 1 <= Ti <= 10000000

4. 1 <= M, Gi <= 1000000000

5. 1 <= Ki < N

6. 1 <= Cij <= N Output For each test case, output the case number first, then the minimum time for Magina to gain at least M units money, if can’t, output “
Poor Magina, you can't save the world all the time!”.
Sample Input
3
1 4
2 5 0
1 5
1 4 0
4 10
1 9 0
3 3 1
3
3 3 2
2 4
4 4 1
3

Sample Output
Case 1: 2
Case 2: Poor Magina, you can't save the world all the time!
Case 3: 10


get技能:

背包可以通过队列模拟!!!

首先加入(0,0)表示dp【0】=0;

那么其他的状态都是由(0,0)这个状态转移过来的,对于每一个物品枚举队列中的元素

判断是否合法,如果合法那么加入滚动数组队列,如果不合法,那么仅仅加入此状态(未放入)。

剪枝的话可以这样:应用优先队列,金钱优先,金钱相同时间小的优先,这样的话在保证金钱大的情况下,

不会让花费更大的进入队列,从而做到了剪枝

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#define INF 0x7ffffff
#define N 55
using namespace std;
struct node
{
int c,w;
} p
;
vector<node> group
;
struct Node
{
int c,w;//c 时间,w 金钱
bool operator<(const Node a)const
{
return w!=a.w?w<a.w:c>a.c; //金钱从大到小,时间从小到大排列;
}
} s;
int ans,cnt,v
,n,m,mp

;
void dfs(int c)
{
v[c]=1;
group[cnt].push_back(p[c]);
for(int i=1; i<=n; i++)
if(!v[i]&&mp[c][i])
dfs(i);
}
void divid()//分组
{
cnt=0;
memset(v,0,sizeof(v));
for(int i=1; i<=n; i++)
if(!v[i])
{
group[cnt].clear();
dfs(i);
cnt++;
}
}

void slove()
{
ans=INF;
priority_queue<Node> q2;
queue<Node>q1;
for(int i=0; i<cnt; i++) //对每组做背包
{
while(!q1.empty())q1.pop();
while(!q2.empty())q2.pop();
s.c=s.w=0;
q1.push(s);
for(int j=0; j<group[i].size(); j++)
{
while(!q1.empty())//对每个状态都考虑第j个物品取不取
{
s=q1.front();
q1.pop();
q2.push(s);
s.c+=group[i][j].c;
s.w+=group[i][j].w;
if(s.w>=m)//剪枝
{
ans=min(ans,s.c);
continue;
}
if(s.c>=ans) continue;//剪枝
q2.push(s);
}
int mincost=INF;
while(!q2.empty())// 滚动数组
{
s=q2.top();
q2.pop();
if(s.c<mincost)//更新状态+剪枝,将时间长且金钱少的状态去掉。
q1.push(s),mincost=s.c;
}
}
}
}

int main()
{
int T,kase=0;
cin>>T;
while(T--)
{
cin>>n>>m;
memset(mp,0,sizeof(mp));
for(int i=1; i<=n; i++)
{
int k;
scanf("%d%d%d",&p[i].c,&p[i].w,&k);
while(k--)
{
int t;
scanf("%d",&t);
mp[i][t]=mp[t][i]=1;
}
}
divid();
slove();
printf("Case %d: ",++kase);
if(ans==INF) printf("Poor Magina, you can't save the world all the time!\n");
else printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: