洛谷1262 间谍网络
题目描述
由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果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,并在第二行输出不能控制的间谍中,编号最小的间谍编号。
题解
先用dfs搜出是否可行,然后用tarjan缩点,记录下每个强连通分量里最小值,重建图。每次收买入度为0的点即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define inf 20000000 6 using namespace std; 7 int n,m,cnt; 8 int dfn[3005],low[3005],head[3005],w[3005],v[3005],q[3005],du[3005],bel[3005],hav[3005]; 9 int top,tot,ans; 10 int x[8005],y[8005]; 11 bool inq[3005],vis[3005]; 12 struct edge{ 13 int next,to; 14 }e[8005]; 15 void insert(int u,int v){ 16 cnt++; 17 e[cnt].next=head[u];e[cnt].to=v; 18 head[u]=cnt; 19 } 20 int ind; 21 void tarjan(int x){ 22 dfn[x]=low[x]=++ind; 23 q[++top]=x; 24 inq[x]=1; 25 for(int i=head[x];i;i=e[i].next){ 26 int s=e[i].to; 27 if(!dfn[s]){ 28 tarjan(s); 29 low[x]=min(low[s],low[x]); 30 } 31 else if(inq[s]){ 32 low[x]=min(low[x],dfn[s]); 33 } 34 } 35 int now=0; 36 if(dfn[x]==low[x]){ 37 tot++; 38 while(now!=x){ 39 now=q[top];top--; 40 bel[now]=tot; 41 inq[now]=0; 42 if(w[now])v[tot]=min(v[tot],w[now]); 43 } 44 } 45 } 46 int k; 47 void dfs(int x){ 48 vis[x]=1;k++; 49 for(int i=head[x];i;i=e[i].next){ 50 if(!vis[e[i].to])dfs(e[i].to); 51 } 52 } 53 int main(){ 54 int p,u,d; 55 scanf("%d",&n); 56 scanf("%d",&p); 57 for(int i=1;i<=p;i++){ 58 scanf("%d%d",&u,&d); 59 //一开始写的是scanf("%d%d",&u,&w[u]);导致w里的值都是0 60 w[u]=d; 61 } 62 scanf("%d",&m); 63 for(int i=1;i<=m;i++){ 64 scanf("%d%d",&x[i],&y[i]); 65 insert(x[i],y[i]); 66 } 67 for(int i=1;i<=n;i++)if(!vis[i]&&w[i])dfs(i); 68 if(k<n){ 69 printf("NO\n"); 70 for(int i=1;i<=n;i++){ 71 if(!vis[i]){ 72 printf("%d",i); 73 return 0; 74 } 75 } 76 } 77 memset(v,127,sizeof v); 78 for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i); 79 cnt=0; 80 memset(head,0,sizeof head); 81 memset(e,0,sizeof e); 82 for(int i=1;i<=m;i++){ 83 if(bel[x[i]]!=bel[y[i]]){ 84 insert(bel[x[i]],bel[y[i]]); 85 du[bel[y[i]]]++; 86 } 87 } 88 for(int i=1;i<=tot;i++){ 89 if(!du[i]){ 90 ans+=v[i]; 91 } 92 } 93 printf("YES\n%d",ans); 94 return 0; 95 }