永不言弃 (topsort+优先队列)

题目链接

题意

小沙最喜欢打怪升级了,今天他玩了一个游戏,需要从初始关卡开始,击败n个关卡才能通关整个游戏,对于每个关卡都会有两种通过方式。

小沙初始的属性值为s,当游戏角色的属性大于关卡最高上限时,可以强行通过该关卡,又或者拥有通过该关卡的必过道具(并不是消耗品)。每个关卡通过后可能会开启一个或多个后置关卡,但每个关卡开启也需要若干个前置关卡,只有前置关卡全部通过后,才能开启该关卡。特别注意,除了一号关卡,如果一个关卡没有任何前置关卡,那么这个关卡则永远无法开启。

每个关卡仅能游玩一次,且每个关卡通过都会增强小沙角色的属性,也会给予一个必过道具。目前小沙正在一号关卡,请问小沙能否将这个游戏打通。

思路:首先每个点需要前驱节点都已经被遍历,刚好满足拓扑排序的顺序,但是由于每个点的后继节点比较多,有可能先遍历到的点不能通过,但是由于后面拿到卡片或者增加了属性,导致之前不能过的点,现在能通过,要将每个有卡片的点的关卡最高上限改为0,然后压入优先队列里,如果某一次优先队列里最小的关卡都不能通过,说明没有路可以走了,如果能遍历结束,说明能够走完。(之前想到的思路是修改掉已经压入队列的点的权值,但是后面发现修改复杂度太高,后面才知道不需要修改,只需要重新压入一个修改过的点即可,然后每个出来的点判断一下之前是否已经出来过就可以去重了)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int val[100010],b[100010];
int gs[100010],gb[100010];
int h[50010];
struct tt{
    int x,to;
};
tt e[500010];
int d[50010];
int idx=0;
priority_queue<pair<ll, ll>, vector<pair<ll, ll>>,greater<pair<ll,ll> > >w;
void add(int a,int b){
    e[idx].x=b,e[idx].to=h[a],h[a]=idx++;
}
int q[50010];
int n,s;
int vis[100010],vvis[100010];
ll sum=0;
vector<int>ans[50100];
bool topsort(){
    sum=s;
    w.push(make_pair(val[1],1));
    while(!w.empty()){
        pair<ll,ll>node=w.top();
        w.pop();
        if(node.first>=sum){
            printf("No\n");
            return 0;
        }
        if(vis[node.second])continue;
        vis[node.second]=1;
        if(!vvis[b[node.second]]){
            vvis[b[node.second]]=1;
            for(int i=0;i<ans[b[node.second]].size();i++){
                pair<ll,ll> ff;
                ff.first=0;
                ff.second=ans[b[node.second]][i];
                //cout<<ff.second<<endl;
                if(!d[ans[b[node.second]][i]])w.push(ff);
            }
        }
        for(int i=h[node.second];i!=-1;i=e[i].to){
            int j=e[i].to;
            d[j]--;
            if(!d[j]){
                pair<ll,ll> ff;
                ff.first=val[j];
                ff.second=j;
                w.push(ff);
            }
        }
    }
    return true;
}
int main(){
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&val[i],&b[i]);
        ans[b[i]].push_back(i);
    }
    for(int i=1;i<=n;i++){
        scanf("%d%d",&gs[i],&gb[i]);
    }
    int k,x;
    for(int i=1;i<=n;i++){
        scanf("%d",&k);
        for(int j=1;j<=k;j++){
            scanf("%d",&x);
            add(i,x);
            d[x]++;
        }
    }
    int flag=true;
    for(int i=2;i<=n;i++){
        if(!d[i]){
            flag=false;
        }
    }
    if(d[1]) flag=false;
    if(!flag)printf("No\n");
    else{
    if(topsort())printf("Yes\n");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值