Loading

洛谷P1262-间谍网络 题解

1262-间谍网络-tarjan

有一些间谍可以被一定金钱收买,控制一个间谍就可以控制它掌握的所有间谍,以此递推下去。求最少用多少钱就可以控制所有间谍。如果不能输出-1。

首先从可以被掌控的间谍那里开始dfs,判断能不能覆盖所有点。若不能输出-1结束。

考虑没有环的情况,入度为0的间谍一定需要被收买,而且只需要收买所有入度为0的间谍就可以控制所有入度不为零的间谍。

如果有环,则需要先tarjan缩点,然后判断环的总入度,同理,只需要收买所有入度为0的点或环就可以控制全部。对于环,我们只需要收买环上的任意一个间谍即可,优先收买代价最小的,遍历环上的间谍即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=5e3+10;

stack<int> k1;
int sp[maxn],dfn[maxn],dfsnum,rd[maxn],dlow[maxn],dfstot;
bool visst[maxn];
bool vistot[maxn];
vector<int> yuan[maxn];
int zhi[maxn];
int n,p,r;
bool vis[maxn],can[maxn];
vector<int> ssp[maxn];
void dfs(int now){
    vis[now]=1;
    for(int i=0;i<yuan[now].size();i++){
        int v=yuan[now][i];
        if(!vis[v]) dfs(v);
    }
}
void tarjan(int now){
    dfn[now]=dlow[now]=++dfsnum;
    k1.push(now);visst[now]=1;
    for(int i=0;i<yuan[now].size();i++){
        int v=yuan[now][i];
        if(!dfn[v]){
            tarjan(v);
            dlow[now]=min(dlow[now],dlow[v]);
        }
        else if(visst[v]) dlow[now]=min(dlow[now],dfn[v]);
    }
    if(dlow[now]==dfn[now]){
        dfstot++;
        while(!k1.empty()){
            int tmp=k1.top();
            k1.pop();
            sp[tmp]=dfstot;
            visst[tmp]=0;
            if(tmp==now) break;
        }
    }
}
int main(){
    cin>>n>>p;
    for(int i=1;i<=p;i++){
        int a1,a2;cin>>a1>>a2;
        zhi[a1]=a2;
        can[a1]=1;
    }
    cin>>r;
    for(int i=1;i<=r;i++){
        int a1,a2;cin>>a1>>a2;
        yuan[a1].push_back(a2);
    }
    for(int i=1;i<=n;i++){
        if(can[i]) dfs(i);
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            cout<<"NO\n"<<i<<endl;
            return 0;
        }
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]) tarjan(i);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<yuan[i].size();j++){
            int v=yuan[i][j];
            if(sp[i]!=sp[v]) rd[sp[v]]++;
            else continue;
        }
    }
    for(int i=1;i<=n;i++) if(can[i]) ssp[sp[i]].push_back(i);
    ll ans=0;
    for(int i=1;i<=n;i++){
        if(zhi[i]){
            if(rd[sp[i]]==0&&!vistot[sp[i]]){
                vistot[sp[i]]=1;
                ll min1=inf;
                for(int j=0;j<ssp[sp[i]].size();j++){
                    int v=ssp[sp[i]][j];
                    min1=min(min1,(ll)zhi[v]);
                }
                ans+=min1;
            }   
        }
    }
    cout<<"YES\n"<<ans<<endl;
    return 0;
}
posted @ 2021-04-16 11:53  14long  阅读(82)  评论(0)    收藏  举报