洛谷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; }
Copyright:http://www.cnblogs.com/candy99/