P1262 间谍网络

P1262 间谍网络

Tarjan缩点

我们用Tarjan缩完点后,剩下若干个DAG图

我们发现,只要每个图的所对应的强连通分量上有某人能被收买,显然整个DAG上的人都能被收买。

于是我们就在Tarjan的过程中顺便维护每个强连通分量的对应最小费用,也就是分量中价格最便宜的那个人。

(终于找到我会写的题了qwq)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
template <typename T> inline T min(T &a,T &b) {return a<b ? a:b;}
template <typename T> inline void read(T &x){
    char c=getchar(); x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
int n,m1,m2,ans,dfs_clock,dfn[3002],low[3002],tot,be[3002],_top,st[3002];
int val1[3002],cnt,hd[3002],nxt[8002],ed[3002],poi[8002];
int val2[3002],cnt2,hd2[3002],nxt2[8002],ed2[3002],poi2[8002];
int in[3002]; bool flag[3002];
inline void add(int x,int y){
    nxt[ed[x]]=++cnt; hd[x]= hd[x] ? hd[x]:cnt;
    ed[x]=cnt; poi[cnt]=y;
}
inline void add2(int x,int y){
    nxt2[ed2[x]]=++cnt2; hd2[x]= hd2[x] ? hd2[x]:cnt2;
    ed2[x]=cnt2; poi2[cnt2]=y;
}
inline void tarjan(int x){
    dfn[x]=low[x]=++dfs_clock; st[++_top]=x;
    for(int i=hd[x];i;i=nxt[i]){
        if(!dfn[poi[i]]) tarjan(poi[i]),low[x]=min(low[x],low[poi[i]]);
        else if(!be[poi[i]]) low[x]=min(low[x],dfn[poi[i]]);
    }
    if(dfn[x]==low[x]){
        be[x]=++tot; val2[tot]=val1[x];
        while(st[_top]!=x) be[st[_top]]=tot,val2[tot]=min(val2[tot],val1[st[_top--]]); //维护强连通分量的最小费用
        --_top;
    }
}
inline void dfs(int x){
    flag[x]=1;
    for(int i=hd2[x];i;i=nxt2[i]) if(!flag[poi2[i]]) dfs(poi2[i]);
}
int main(){
    memset(val1,127,sizeof(val1));
    memset(val2,127,sizeof(val2));
    read(n); read(m1); int q1,q2;
    for(int i=1;i<=m1;++i) read(q1),read(q2),val1[q1]=q2;
    read(m2);
    for(int i=1;i<=m2;++i) read(q1),read(q2),add(q1,q2);
    for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;++i) //建新图
        for(int j=hd[i];j;j=nxt[j])
            if(be[i]!=be[poi[j]])
                add2(be[i],be[poi[j]]),++in[be[poi[j]]];
    bool ok=1;
    for(int i=1;i<=tot;++i)
        if(!in[i]){ //树根
            if(val2[i]==val2[0]) ok=0; //没有间谍可收买
            ans+=val2[i];
        }
    if(ok) printf("YES
%d",ans);
    else{
        for(int i=1;i<=tot;++i) if(!in[i]&&val2[i]==val2[0]) dfs(i); //dfs找出所有解决不了的块
        for(int i=1;i<=n;++i) if(flag[be[i]]&&val1[i]==val1[0]) {printf("NO
%d",i); break;} //注意单个间谍也不可以被收买 
    }return 0;
}
原文地址:https://www.cnblogs.com/kafuuchino/p/9691239.html