1. 程式人生 > >間諜網絡

間諜網絡

什麽 else tdi ons fault clas cst tarjan 需要

★★ 輸入文件:spyweb.in 輸出文件:spyweb.out 簡單對比
時間限制:1 s 內存限制:128 MB

【問題描述】

由於外國間諜的大量滲入,國家安全正處於高度的危機之中。如果A間諜手中掌握著關於B間諜的犯罪證據,則稱A可以揭發B。有些間諜收受賄賂,只要給他們一定數量的美元,他們就願意交出手中掌握的全部情報。所以,如果我們能夠收買一些間諜的話,我們就可能控制間諜網中的每一分子。因為一旦我們逮捕了一個間諜,他手中掌握的情報都將歸我們所有,這樣就有可能逮捕新的間諜,掌握新的情報。

我們的反間諜機關提供了一份資料,包括所有已知的受賄的間諜,以及他們願意收受的具體數額。同時我們還知道哪些間諜手中具體掌握了哪些間諜的資料。假設總共有n個間諜(n不超過3000),每個間諜分別用1到3000的整數來標識。

請根據這份資料,判斷我們是否有可能控制全部的間諜,如果可以,求出我們所需要支付的最少資金。否則,輸出不能被控制的一個間諜。

【輸入】

輸入文件age.in第一行只有一個整數n。

第二行是整數p。表示願意被收買的人數,1≤p≤n。

接下來的p行,每行有兩個整數,第一個數是一個願意被收買的間諜的編號,第二個數表示他將會被收買的數額。這個數額不超過20000。

緊跟著一行只有一個整數r,1≤r≤8000。然後r行,每行兩個正整數,表示數對(A, B),A間諜掌握B間諜的證據。

【輸出】

答案輸出到age.out。

如果可以控制所有間諜,第一行輸出YES,並在第二行輸出所需要支付的賄金最小值。否則輸出NO,並在第二行輸出不能控制的間諜中,編號最小的間諜編號。

【樣例1】

age.in age.out

3 YES

2 110

1 10

2 100

2

1 3

2 3

【樣例2】

age.in age.out

4 NO

2 3

1 100

4 200

2

1 2

3 4

思路

先對所有的可收買的點按收買價格排序;

然後每個點如果需要加入,更新他之前點的影響,並記錄該點的影響;

如果有一個點沒有影響源,該點不受控制;

對於所有可以收買的點,如果影響為0,不收買;

代碼實現

 1     #include<cstdio>
 2     #include<cstring>
 3     #include<algorithm>
 4     using namespace std;
 5     const int maxn=3010;
 6     const int maxr=8010;
 7     int n,p,r,ans;
 8     int a,b;
 9     int h[maxn],hs;
10     int e_s[maxr],e_n[maxr];
11     int f[maxn],nd[maxn];
12     struct nate{int s,v;}d[maxn];
13     bool cmp(const nate&x,const nate&y){return x.v<y.v;}
14     void dfs(int k,int s){
15         if(f[k]) nd[f[k]]--;
16         f[k]=s,nd[s]++;
17         for(int i=h[k];i;i=e_n[i])
18         if(f[e_s[i]]!=s) dfs(e_s[i],s);
19     }
20     int main(){
21         freopen("spyweb.in","r",stdin);
22         freopen("spyweb.out","w",stdout);
23         scanf("%d%d",&n,&p);
24         for(int i=1;i<=p;i++){
25             scanf("%d%d",&a,&b);
26             d[i].s=a,d[i].v=b;
27         }
28         sort(d+1,d+p+1,cmp);
29         scanf("%d",&r);
30         for(int i=1;i<=r;i++){
31             scanf("%d%d",&a,&b);
32             ++hs,e_s[hs]=b,e_n[hs]=h[a],h[a]=hs;
33         }
34         for(int i=1;i<=p;i++){
35             if(f[d[i].s]) for(int j=h[d[i].s];j;j=e_n[j]){
36                 if(!f[e_s[j]]){
37                     dfs(d[i].s,i);
38                     break;
39                 }
40             }
41             else dfs(d[i].s,i);
42         }
43         for(int i=1;i<=n;i++)
44         if(!f[i]){
45             printf("NO\n%d\n",i);
46             return 0;
47         }
48         for(int i=1;i<=p;i++) if(nd[i]) ans+=d[i].v;
49         printf("YES\n%d\n",ans);
50         return 0;
51     }

R了一遍,W了一遍,都是些碼代碼時的疏漏。

該題有Tarjan的做法,但我不想寫。(Tarjan什麽鬼???)

間諜網絡