题意:
有n堆野兽,每堆野兽屠杀完完需要花费ti时间,可以增加金钱gi,敌法师有瞬移技能,可以从某堆野兽移到另一堆野兽,题目有给定从哪堆可以移到哪堆。最后问在满足打的金钱多余m的情况下的最少时间。
分析:
如果题目数据范围小点,那么就是一个01背包的板题了,只要在连通块上进行背包就可以了,但是题意M最大是1e9,显然得考虑优化策略,因为自己的知识有限,所以参考的大佬的优化方法,很机智,用优先队列进行模拟,同时进行剪枝就好了,注意一点就是如果当前获得的钱比另一个少,但是花费的时间不比他少那么直接剪了这个状态就好了 。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<string>
#include<queue>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
struct node{
int x,y; //time money
friend bool operator < (node a,node b){
if(a.y==b.y) return a.x>b.x;
return a.y<b.y;
}
};
int fa[55];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
priority_queue<node> q[2];
int t[55],g[55];
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T;
scanf("%d",&T);
for(int cs=1;cs<=T;cs++){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=n;i++){
int k;
scanf("%d%d%d",&t[i],&g[i],&k);
while(k--){
int x;
scanf("%d",&x);
fa[find(x)]=find(i);
}
}
node fx{0,0};
int ans=inf;
for(int i=1;i<=n;i++){
if(fa[i]==i){
while(!q[0].empty()) q[0].pop();
while(!q[1].empty()) q[1].pop();
q[0].push(fx);
for(int j=1;j<=n;j++){
if(fa[j]==i){
while(!q[0].empty()){
node tmp=q[0].top();
q[0].pop();
q[1].push(tmp);
node now;
now.x=tmp.x+t[j];
now.y=tmp.y+g[j];
if(now.y>=m){
ans=min(now.x,ans);
continue;
}
if(now.x>=ans){
continue;
}
q[1].push(now);
}
int x=inf;
while(!q[1].empty()){
node now=q[1].top();
q[1].pop();
if(now.x<x){
x=now.x;
q[0].push(now);
}
if(now.y>=m){
ans=min(ans,now.x);
}
}
}
}
}
}
if(ans==inf){
printf("Case %d: Poor Magina, you can't save the world all the time!\n",cs);
}else{
printf("Case %d: %d\n",cs,ans);
}
}
return 0;
}