HDU - 3810 Magina (并查集+优先队列优化背包)

题意:

有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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值