洛谷P1262 间谍网络[强连通分量 BFS]

题目描述

由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B。有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报。所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子。因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报。

我们的反间谍机关提供了一份资料,色括所有已知的受贿的间谍,以及他们愿意收受的具体数额。同时我们还知道哪些间谍手中具体掌握了哪些间谍的资料。假设总共有n个间谍(n不超过3000),每个间谍分别用1到3000的整数来标识。

请根据这份资料,判断我们是否有可能控制全部的间谍,如果可以,求出我们所需要支付的最少资金。否则,输出不能被控制的一个间谍。

输入输出格式

输入格式:

 

第一行只有一个整数n。

第二行是整数p。表示愿意被收买的人数,1≤p≤n。

接下来的p行,每行有两个整数,第一个数是一个愿意被收买的间谍的编号,第二个数表示他将会被收买的数额。这个数额不超过20000。

紧跟着一行只有一个整数r,1≤r≤8000。然后r行,每行两个正整数,表示数对(A, B),A间谍掌握B间谍的证据。

 

输出格式:

 

如果可以控制所有间谍,第一行输出YES,并在第二行输出所需要支付的贿金最小值。否则输出NO,并在第二行输出不能控制的间谍中,编号最小的间谍编号。

 

输入输出样例

输入样例#1:
【样例1】
3
2
1 10
2 100
2
1 3
2 3
【样例2】
4
2
1 100
4 200
2
1 2
3 4
输出样例#1:
【样例1】
YES
110
【样例2】
NO
3

很明显的tarjan求scc,然后选择每个入度为0的scc里贿金最小的间谍
判断有无解当然可以求完scc后新建图dfs,也可以先把所有可以贿赂的间谍入队BFS一遍
//
//  main.cpp
//  luogu1262
//
//  Created by Candy on 11/11/2016.
//  Copyright ? 2016 Candy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=3005,M=8005,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,nn,u,v,w[N];
struct edge{
    int v,ne;
}e[N<<1];
int h[N],cnt=0;
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
}
struct person{
    int id,w;
}p[N];
int fw[N];
int vis[N],q[N],head=1,tail=1;
int bfs(){
    for(int i=1;i<=nn;i++) {q[tail++]=p[i].id;vis[p[i].id]=1;}
    while(head!=tail){
        int u=q[head++];
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]) continue;
            vis[v]=1;
            q[tail++]=v;
        }
    }
    for(int i=1;i<=n;i++) if(!vis[i]) return i;
    return 0;
}

int dfn[N],low[N],belong[N],dfc,scc;
int st[N],top;
void dfs(int u){
    dfn[u]=low[u]=++dfc;
    st[++top]=u;
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(!dfn[v]){
            dfs(v);
            low[u]=min(low[u],low[v]);
        }else if(!belong[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        scc++;
        while(true){
            int x=st[top--];
            belong[x]=scc;
            if(x==u) break;
        }
    }
}
void SCC(){
    for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
}
int mn[N],ind[N];
int sol(){
    memset(mn,127,sizeof(mn));
    for(int i=1;i<=nn;i++){
        int x=p[i].id,w=p[i].w;
        mn[belong[x]]=min(mn[belong[x]],w);
    }
    for(int u=1;u<=n;u++)
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(belong[u]!=belong[v]) ind[belong[v]]++;
        }
    int ans=0;
    for(int i=1;i<=scc;i++) if(ind[i]==0) ans+=mn[i];
    return ans;
}
int main(){
    n=read();nn=read();
    for(int i=1;i<=nn;i++) p[i].id=read(),p[i].w=read();
    m=read();
    for(int i=1;i<=m;i++){u=read();v=read();ins(u,v);}
    
    int x=bfs();
    if(x){printf("NO\n%d",x);return 0;}
    
    SCC();
    printf("YES\n%d",sol());
    return 0;
}

 

 
posted @ 2016-11-11 14:13  Candy?  阅读(327)  评论(0编辑  收藏  举报