fzu 1719 强连通分量 缩点

题意:有n个间谍,其中r个花钱可以买通,间谍手上有其他间谍的证据。问能否控制所有间谍。能的话输出最小的钱数,不能的话输出最小的不能被控制的间谍ID。

分析:缩点后的价值取环内最小的价值,然后把入度为0的间谍全部买下来。

 

 

#define M 3011
struct Node{
    int v,next;//next要初始化为-1
}edge[15001];
int n , nn , len;
int old[M],now[M];
int tim[M],t;
int low[M],hash[M],hp[M];//原结点向新结点映射  新边判重
int sta[M],top;

int cost[M];
int sum,minid;
int id[M],s[M],rudu[M];

void dfs(int u) {
    tim[u] = low[u] = t ++;
    sta[++top] = u;
    for(int i = old[u] ; i != -1 ; i = edge[i].next) {
        int v = edge[i].v;
        if(tim[v] == -1) {
            dfs(v);
            checkmin(low[u],low[v]);
        } else if(hash[v] == -1) {
            checkmin(low[u],low[v]);//low[v]貌似也可以???
        }
    }
    if(tim[u] == low[u]) {

        id[nn]=-1,s[nn]=99999999;

        int v = -1;
        while(u != v) {
            v = sta[top--];
            checkmin(id[nn],v);
            if(cost[v]>0 && s[nn]>cost[v]) s[nn]=cost[v];
            hash[v] = nn;
        }
        rudu[nn]=0;
        now[nn++] = -1;
    }
}

void Trajan() {
    FOR(i,1,n+1) if(tim[i] == -1) {
        dfs(i);
    }
    FOR(u,1,n+1) {
        for(int i = old[u] ; i != -1 ; i = edge[i].next) {
            int v = edge[i].v;
            if(hash[u] != hash[v] && hp[hash[u]] != hash[v]) {
                rudu[ hash[v] ] ++;
                hp[hash[u]] = hash[v];  //新边的判重貌似有问题
                edge[len].next = now[ hash[u] ];
                edge[len].v = hash[v];
                now[ hash[u] ] = len++;
            }
        }
    }
}

void init(){
    memset(old,-1,sizeof(int)*(n+1));
    memset(tim,-1,sizeof(int)*(n+1));
    memset(hash,-1,sizeof(int)*(n+1));
    memset(hp,-1,sizeof(int)*(n+1));
    memset(cost,-1,sizeof(int)*(n+1));
    len = t = top = nn = sum = 0;
    minid=-1;
}

void build(){
    int r,a,b;
    cin>>r;
    FF(i,r){
        cin>>a>>b;
        edge[len].next=old[a];
        edge[len].v=b;
        old[a]=len++;
    }
}

void d(int u){
    checkmin(minid,id[u]);
    for(int i=now[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(s[v]>=9999999) d(v);
    }
}

int main()
{
    while(cin>>n){
        init();
        int p,a,b;
        cin>>p;
        FF(i,p){
            cin>>a>>b;
            cost[a]=b;
        }
        build();
        Trajan();

        FF(i,nn){
            if(rudu[i]==0){
                if(s[i]<9999999)sum+=s[i];
                else d(i);
            }
        }

        if(minid!=-1)cout<<"NO"<<endl<<minid<<endl;
        else cout<<"YES"<<endl<<sum<<endl;
    }
    return 0;
}

 

posted @ 2013-06-21 12:46  心向往之  阅读(195)  评论(0编辑  收藏  举报