P1262 间谍网络
题目描述
由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果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缩点 建新图 统计入度若只有一个点 即整张图为环 判断是否有人被收买 若有入度为0的点 且没有被收买 则为NO从入度为0的点遍历新图 若有点没有遍历到 则为NO否则为YES
1 #include <queue> 2 #include <cstdio> 3 #include <cctype> 4 #include <cstring> 5 6 const int INF=0x3f3f3f3f; 7 const int MAXN=3010; 8 const int MAXM=8010; 9 10 int n,p,r,inr,id,ans,top; 11 12 int fee[MAXN],dfn[MAXN],low[MAXN],stack[MAXN],belong[MAXN],Money[MAXN],In[MAXN]; 13 14 bool vis[MAXN]; 15 16 struct node { 17 int to; 18 int next; 19 node() {} 20 node(int to,int next):to(to),next(next) {} 21 }; 22 node e[MAXN<<1],Edge[MAXN<<1]; 23 24 int head[MAXN],tot,Head[MAXN],TOT; 25 26 inline void read(int&x) { 27 int f=1;register char c=getchar(); 28 for(x=0;!isdigit(c);c==‘-‘&&(f=-1),c=getchar()); 29 for(;isdigit(c);x=x*10+c-48,c=getchar()); 30 x=x*f; 31 } 32 33 inline int min(int a,int b) {return a<b?a:b;} 34 35 inline bool pd(int u,int v) { 36 for(int i=Head[u];i;i=Edge[i].next) if(v==Edge[i].to) return true; 37 return false; 38 } 39 40 inline void add(int x,int y) { 41 e[++tot]=node(y,head[x]); 42 head[x]=tot; 43 } 44 45 void tarjan(int u) { 46 dfn[u]=low[u]=++inr; 47 stack[++top]=u; 48 vis[u]=true; 49 for(int i=head[u];i;i=e[i].next) { 50 int v=e[i].to; 51 if(!dfn[v]) { 52 tarjan(v); 53 low[u]=min(low[u],low[v]); 54 } 55 else if(vis[v]) low[u]=min(low[u],dfn[v]); 56 } 57 if(dfn[u]==low[u]) { 58 ++id; 59 int t; 60 do { 61 t=stack[top--]; 62 if(fee[t]) Money[id]=min(Money[id],fee[t]); 63 vis[t]=false; 64 belong[t]=id; 65 }while(u!=t); 66 } 67 } 68 69 inline void build_NEW() { 70 memset(vis,false,sizeof vis); 71 for(int i=1;i<=n;++i) 72 for(int j=head[i];j;j=e[j].next) { 73 int v=e[j].to; 74 if(belong[i]==belong[v]) continue; 75 if(pd(belong[i],belong[v])) continue; 76 ++In[belong[v]]; 77 Edge[++TOT]=node(belong[v],Head[belong[i]]); 78 Head[belong[i]]=TOT; 79 } 80 return; 81 } 82 83 int hh() { 84 read(n);read(p); 85 for(int x,y,i=1;i<=p;++i) read(x),read(y),fee[x]=y; 86 read(r); 87 for(int x,y,i=1;i<=r;++i) { 88 read(x);read(y); 89 add(x,y); 90 } 91 memset(Money,INF,sizeof Money); 92 for(int i=1;i<=n;++i) 93 if(!dfn[i]) tarjan(i); 94 if(id==1) { 95 if(Money[1]==INF) printf("NO\n%d\n",1); 96 else printf("YES\n%d\n",Money[1]); 97 return 0; 98 } 99 build_NEW(); 100 for(int i=1;i<=n;++i) 101 if(!In[belong[i]]&&Money[belong[i]]==INF) { 102 printf("NO\n%d\n",i); 103 return 0; 104 } 105 std::queue<int> q; 106 for(int i=1;i<=id;++i) if(!In[i]&&Money[i]) q.push(i),vis[i]=true,ans+=Money[i]; 107 while(!q.empty()) { 108 int u=q.front(); 109 q.pop(); 110 for(int i=Head[u];i;i=Edge[i].next) { 111 int v=Edge[i].to; 112 if(!vis[v]) { 113 vis[v]=true; 114 q.push(v); 115 } 116 } 117 } 118 for(int i=1;i<=n;++i) if(!vis[belong[i]]) {printf("NO\n%d\n",i);return 0;} 119 printf("YES\n%d\n",ans); 120 return 0; 121 } 122 123 int sb=hh(); 124 int main(int argc,char**argv) {;}
代码
时间: 2024-10-12 21:19:38