洛谷 P1262 间谍网络

                                           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) {;}
代码

 

posted @ 2017-09-08 18:06  拿叉插猹哈  阅读(224)  评论(0编辑  收藏  举报