万妖瞬击

Problem Description
“万妖穴中有若干小穴,每处小穴中皆有一只恶妖。小穴外设有封印,汝需消灭指定几处小穴中的恶妖方能解除该小穴封印,进而消灭穴中恶妖。”

“此处石壁所刻便是万妖穴中各穴的封印解除关系。”

“吾将瞬雷之法授于汝,汝消灭万妖穴中任一小穴皆仅需一瞬,愿汝尽快消灭各穴恶妖。”

“然消灭小穴后,其对下一处小穴的封印加强通道仍需若干时间方能闭上。”

“万妖穴中气息诡谲,恐有恶灵干扰,将使此段通道关闭时间变长。”

“汝需施法避免几处关键通道免于干扰,以使消灭整个万妖穴的时间免于延长。”

“万妖穴中或有部分小穴未设封印,汝可以此作为突破口。”

“吾将根据石壁所示,将各穴消灭顺序给予汝,汝自珍重。”

Input
每个输入文件中一组数据。
第一行两个正整数N、M(1<=N<=1000,0<=M<=N*(N-1)),表示万妖穴中小穴的个数及封印解除关系的条数。
接下来M行,每行三个整数a、b、c(0 <= a < N, 0 <= b < N, 0 < c <= 20),表示小穴b封印的解除依赖于消灭小穴a中的恶妖,且消灭小穴a中的恶妖后需要时长c才能关闭其对小穴b的封印加强通道(注意,必须将小穴b依赖的所有小穴中的恶妖消灭、并等待针对小穴b的封印加强通道都关闭后才能消灭小穴b)。假设N处小穴的编号分别是0~N-1。数据保证a不等于b,且每组封印解除关系a b最多出现一次。

Output
如果能够消灭所有小穴,那么在第一行输出YES与消灭所有恶妖的总时长,中间用一个空格隔开。然后从第二行开始输出关键路径,格式为用->连接的小穴编号。所谓关键路径是指,此路径上的所有通道的关闭时间均不可以被延长,否则会使消灭所有恶妖的时间变长;且关键路径上所有通道的关闭时长之和就是消灭所有恶妖的总时长。如果有多条关键路径,那么每行输出一条。注意,假设有两条关键路径a[1]->a[2]->…->a[k]->a[k+1]->…与b[1]->b[2]->…->b[k]->[k+1]->…,且a[1]==b[1]、a[2]==b[2]、…、a[k]==b[k]、a[k+1]< b[k+1],那么把关键路径a优先输出。数据保证关键路径条数不超过10000条。

如果不能消灭所有小穴,那么只输出一行,即NO与无法解除封印的小穴个数,中间用一个空格隔开。行末均不允许输出多余的空格。

Sample Input 1
5 6
0 1 3
0 3 4
0 2 1
1 3 1
2 3 2
4 0 2

Sample Output 1
YES 6
4->0->1->3
4->0->3

Sample Input 2
3 3
0 1 1
1 0 1
2 0 1

Sample Output 2
NO 2

Author
Shoutmon

Source
18浙大考研机试模拟赛

#include <bits/stdc++.h>
using namespace std;
vector<int> vx[1024],vy[1024],path[1024];
vector<vector<int>> v;
int A[1024][1024],indegree[1024],in[1024];
int ve[1024],vl[1024],n,m;
stack<int> stk;
bool topological()
{
    queue<int> q;
    for(int i=0;i<n;++i){
        if(indegree[i]==0) q.push(i);
    }
    while(!q.empty()){
        int x=q.front();
        q.pop();
        stk.push(x);
        for(int y:vx[x]){
            indegree[y]--;
            if(indegree[y]==0) q.push(y);
            ve[y]=max(ve[x]+A[x][y],ve[y]);
        }
    }
    return (int)stk.size()==n;
}
int criticalpath()
{
    if(topological()==0) return -1;
    int maxval=*max_element(ve,ve+n);
    fill(vl,vl+n,maxval);
    while(!stk.empty()){
        int y=stk.top();
        stk.pop();
        for(int x:vy[y])
            vl[x]=min(vl[x],vl[y]-A[x][y]);
    }
    for(int x=0;x<n;++x){
        for(int y:vx[x]){
            int e=ve[x],l=vl[y]-A[x][y];
            if(e==l) path[x].push_back(y);
        }
    }
    return maxval;
}
void dfs(int x,vector<int> &rp)
{
    if(path[x].size()==0){
        v.push_back(rp);
        return;
    }
    for(int y:path[x]){
        rp.push_back(y);
        dfs(y,rp);
        rp.pop_back();
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;++i){
        int x,y,w;
        scanf("%d %d %d",&x,&y,&w);
        vx[x].push_back(y);
        vy[y].push_back(x);
        A[x][y]=A[y][x]=w;
        indegree[y]++;
        in[y]++;
    }
    int res=criticalpath();
    if(res==-1) printf("NO %d\n",n-(int)stk.size());
    else{
        printf("YES %d\n",res);
        for(int i=0;i<n;++i){
            if(in[i]==0&&path[i].size()!=0){
                vector<int> rp(1,i);
                dfs(i,rp);
            }
        }
        sort(v.begin(),v.end());
        for(auto &p:v){
            int len=p.size();
            for(int i=0;i<len;++i)
                i==len-1?printf("%d\n",p[i]):printf("%d->",p[i]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值