1. 程式人生 > >縮點【洛谷P1262】 間諜網絡

縮點【洛谷P1262】 間諜網絡

ios top 問題 ems tchar ++ 技術分享 是否 string

【洛谷P1262】 間諜網絡

題目描述

由於外國間諜的大量滲入,國家安全正處於高度的危機之中。如果A間諜手中掌握著關於B間諜的犯罪證據,則稱A可以揭發B。有些間諜收受賄賂,只要給他們一定數量的美元,他們就願意交出手中掌握的全部情報。所以,如果我們能夠收買一些間諜的話,我們就可能控制間諜網中的每一分子。因為一旦我們逮捕了一個間諜,他手中掌握的情報都將歸我們所有,這樣就有可能逮捕新的間諜,掌握新的情報。

我們的反間諜機關提供了一份資料,包括所有已知的受賄的間諜,以及他們願意收受的具體數額。同時我們還知道哪些間諜手中具體掌握了哪些間諜的資料。假設總共有n個間諜(n不超過3000),每個間諜分別用1到3000的整數來標識。

請根據這份資料,判斷我們是否有可能控制全部的間諜,如果可以,求出我們所需要支付的最少資金。否則,輸出不能被控制的一個間諜。

一個環內的點當做一個點,進行有向圖縮點,縮點之後的點權就是該點包括的點的點權最小值。

之後重新建圖,對於每個點如果他的點權不是無限大,那麽就可以從他開始擴展,dfn就可以解決。不過有一點問題,就是如果可以遍歷所有點,那麽我們是需要輸出最小代價的。

那麽嘗試hack一下現在的做法。

可以發現,確實會有地方多計算了點權。

比如下面這個圖。

技術分享圖片

按照當前做法,1號點的點權10也會被計算到答案裏,但是我們只需要5號點的點權20就可以了。

所以就有了一個優化,就是統計重新建圖之後每個點的入度,然後從入度為零的點開始遍歷。

之後再去從入度不為零的點遍歷。

code:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int wx=50017;

inline int read(){
    int sum=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    return sum*f;
}

int tot,st[wx],top,col,n,p,m;
int head[wx],h[wx],num,Num;
int dfn[wx],low[wx],belong[wx],size[wx],a[wx],v[wx],vis[wx];
int in[wx];

struct e{
    int nxt,to;
}edge[wx*2];

void add(int from,int to){
    edge[++num].nxt=head[from];
    edge[num].to=to;
    head[from]=num;
}

void Tarjan(int u){
    dfn[u]=low[u]=++tot;
    st[++top]=u;
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!belong[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]){
        belong[u]=++col;
        size[col]++;
        while(st[top]!=u){
            belong[st[top]]=col;
            size[col]++;
            top--;
        }
        top--;
    }
}

struct node{
    int nxt,to;
}e[wx*2];

void Add(int from,int to){
    e[++Num].nxt=h[from];
    e[Num].to=to;
    h[from]=Num;
}

void dfs(int u){
    vis[u]=1;
    for(int i=h[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v])continue;
        dfs(v);
    }
}

int main(){
    n=read(); p=read();
    memset(a,0x3f,sizeof a);
    memset(v,0x3f,sizeof v);
    for(int i=1;i<=p;i++){
        int x; x=read(); a[x]=read();
    }
    m=read();
    for(int i=1;i<=m;i++){
        int x,y;
        x=read(); y=read();
        add(x,y);
    }
    for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
    for(int i=1;i<=n;i++)v[belong[i]]=min(v[belong[i]],a[i]);
    for(int u=1;u<=n;u++){
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(belong[v]!=belong[u])in[belong[v]]++,Add(belong[u],belong[v]);
        }
    }
    int ans=0;
    
    for(int i=1;i<=col;i++){
        if(v[i]!=0x3f3f3f3f&&vis[i]==0&&in[i]==0){
            if(i==1)
            vis[i]=1;ans+=v[i];dfs(i);
        }
    }
    
    for(int i=1;i<=col;i++){
        if(v[i]!=0x3f3f3f3f&&vis[i]==0){
            if(i==1)
            vis[i]=1;ans+=v[i];dfs(i);
        }
    }
    
    for(int i=1;i<=n;i++){
        if(!vis[belong[i]]){
            puts("NO");
            printf("%d\n",i); return 0;
        }
    }
    puts("YES");
    printf("%d\n",ans);
    return 0;
}

縮點【洛谷P1262】 間諜網絡