Magina
题目链接: HDU 3810 Magina
某些怪物是联通的,Magina每次只能选择一个堆进行打怪,也就是分组的01背包,最后如果有解的话,肯定是在打某个堆的某些怪物。因为这个题的时间最大为10亿,我们不能开一个10亿大小的数组。所以用优先队列解决01背包问题,同时进行减枝。
怎么用优先队列解决01背包,思想可以看如下链接:
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define INF 0x3f3f3f3f
#define NUM 100001
using namespace std;
struct node{
int t, g;
friend bool operator < (node a, node b) {
// 这里把 < 理解成优先级大小
if(a.g == b.g)
// 当a和b的金钱是一样的时候,时间更大的优先级更低
return a.t > b.t;
else
// 当a和b的金钱不一样的时候,金钱少的优先级更低
return a.g < b.g;
}
};
int visit[55], ans, M;
vector<int> group[55];
node monster[55];
priority_queue<node> q[2];
void dfs(int id) {
visit[id] = 1;
node p;
// q[0]存放的是当前上一次打怪后的结果,存在多个结果,每个结果对应一种可能性
while(!q[0].empty()) {
p = q[0].top();
q[0].pop();
// 这个加入的是,选择不打当前的怪物结果
q[1].push(p);
// 这里对p进行了操作,选择打当前的怪物结果会怎么样
p.t += monster[id].t;
p.g += monster[id].g;
// 如果打完当前怪,金钱够了,则当前的怪为当前顺序下可打的最后一个怪,因为再打下去的话,
// 获得更多的钱,花更过的时间没有意义,结果不加入队列里
if(p.g >= M) {
// 如果发现用的时间更少,更新ans
if(p.t < ans) {
ans = p.t;
}
continue;
}
else {
// 如果打完当前怪,没有得到所要求的的钱,同时花的时间还比当下的最好结果多,则不再往下打怪,即当前结果不进入队列
if(p.t >= ans)
continue;
// 虽然没打够钱,但是目前所用的时间少于当前的最优解,则说明此条道路上存在可能超过当前最优解的解,结果加入队列
q[1].push(p);
}
}
int temp;
temp = ans;
// 把q1的结果存放到q0里面,为以后是否选择下一个怪物做准备
while(!q[1].empty()) {
p = q[1].top();
q[1].pop();
// 因为q是一个最大堆,堆顶的元素是时间少,金钱多的结果,这里减枝的话,减掉的是花费更多时间,同时金钱更少的结果
// 比如a.t=5,a.g=10, b.t=6, b.g=10, c.t=3, c.g=9 很明显结果b不可能得到比a更好的解,我们就直接不考虑结果b了,但c可能存在更好的解
// 在队列中,金钱一定是从大到小排序的,但是时间不一定,比如上面abc三个结果,排序后,a,b,c
if(p.t < temp) {
q[0].push(p);
temp = p.t;
}
}
for(int i=0; i<group[id].size(); i++) {
if(visit[group[id][i]]) continue;
dfs(group[id][i]);
}
}
int main()
{
int N, T, t, k, b;
node p;
scanf("%d", &T);
for(t=1; t<=T; t++) {
memset(visit, 0, sizeof(visit));
scanf("%d%d", &N, &M);
for(int i=1; i<=N; i++) {
group[i].clear();
scanf("%d%d%d", &monster[i].t, &monster[i].g, &k);
while(k--) {
scanf("%d", &b);
group[i].push_back(b);
}
}
ans = INF;
for(int i=1; i<=N; i++) {
if(visit[i])
continue;
while(!q[0].empty()) q[0].pop();
while(!q[1].empty()) q[1].pop();
p.g = p.t = 0;
q[0].push(p);
dfs(i);
}
printf("Case %d: ", t);
if(ans != INF) {
printf("%d\n", ans);
}
else printf("Poor Magina, you can't save the world all the time!\n");
}
return 0;
}