1. 程式人生 > >[Luogu 1262] 間諜網絡

[Luogu 1262] 間諜網絡

最小 fail tac 資料 步驟 調試 target 一起 isdigit

題目描述

 由於外國間諜的大量滲入,國家安全正處於高度的危機之中。如果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:
3
2
1 10
2 100
2
1 3
2 3

輸出樣例#1:

YES
110
輸入樣例#2:
4
2
1 100
4 200
2
1 2
3 4

輸出樣例#2:

NO
3

My Solution :

還不是很懂 Tarjan 縮點的戳這裏w -> 簡要了解 Tarjan 縮點!

感覺很神奇的一道題,讓我僅僅是按照思路實現一遍代碼就用了一個小時,結果沒過樣例;又調試了半個小時才過。

涉及到以下步驟:

 1、染色縮點:Tarjan 染色縮點同時處理連通塊個數(很簡單而且個數這個好像沒卵用);

 2、重新建圖:按照縮點後的圖重新建圖,並統計新圖的入度,以便於之後的搜索(之前做過的題都沒必要有這個步驟……可能那就是裸題吧);

 3、初始化花費:若一個點(以下提到的均為縮點後的點,即連通塊)中有可收買的間諜,則這個點可控制,將其收買的價值 cost[](初值為 0x3f3f3f3f)取 min 更新,為收買它要用的最少金額;

 4、深搜更新:更新從一個點 u 能到達的點 v 即 v 能被 u 所控制,故從入度為零的點開始 Dfs,更新每個點被控制所需的最小價格(記得過程中也要取 min,因為也許始點不能被控制而路徑上出現了能被收買的點,不取 min 會影響第 5 步中的判斷,詳見代碼,這裏讓我WA了一個點);

 5、枚舉判斷:最後枚舉所有間諜,查詢 cost[ col[i] ](即控制其所在連通塊的最小價值)是否仍為 0x3f3f3f3f,如果是,則此間諜無法被控制,GG;否則輸出 ans;

 6、輸出答案:關於 ans,即收買最小金額的統計,因為入度為 0 的點只能進行收買而無法被控制,所以 ans 即為第 3 步之後,所有入度為零的點的 cost[] 之和,在第 4 步中一起統計好即可。

放個雜亂的代碼,Tarjan 真是太有用了:

 1 #include <queue>
 2 #include <cstdio>
 3 #include <cctype>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 const int maxn = 3000 + 10;
10 const int maxm = 8000 + 10;
11 int n, m, p, head[maxn], dfn_num, col_num, edge_num;
12 int buy[maxn], val[maxn], deg[maxn], cost[maxn], con[maxn];
13 int dfn[maxn], low[maxn], vis[maxn], col[maxn], cnt[maxn], stack[maxn], top;
14 
15 struct Edge{ int u, v, nxt; }edge[maxm];
16 
17 inline int read() {
18   register char ch = 0; register int w = 0, x = 0;
19   while( !isdigit(ch) ) w |= (ch == -), ch = getchar();
20   while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar();
21   return w ? -x : x;
22 }
23 
24 inline void Add_edge(int u, int v) {
25   edge[++edge_num].u = u, edge[edge_num].v = v;
26   edge[edge_num].nxt = head[u], head[u] = edge_num;
27 }
28 
29 void Tarjan(int s) {
30   dfn[s] = low[s] = ++dfn_num;
31   vis[s] = 1, stack[++top] = s;
32   for(int i = head[s]; i; i = edge[i].nxt) {
33     if( !dfn[edge[i].v] ) {
34       Tarjan(edge[i].v), low[s] = min(low[s], low[edge[i].v]);
35     } else if( vis[edge[i].v] ) low[s] = min(low[s], dfn[edge[i].v]);
36   }
37   if( dfn[s] == low[s] ) {
38     col[s] = ++col_num, cnt[col_num] = 1;
39     while( stack[top] != s ) {
40       col[stack[top]] = col_num, ++cnt[col_num];
41       vis[stack[top]] = 0, --top;
42     }
43     vis[s] = 0, --top;
44   }
45 }
46 
47 void Deep_fs(int x, int price) {
48   for(int i = head[x]; i; i = edge[i].nxt) {
49     cost[edge[i].v] = min(cost[edge[i].v], price);
50     Deep_fs(edge[i].v, min(cost[edge[i].v], price));
51   }
52 }
53 
54 inline void Failed(int x) { printf("NO\n%d\n", x), exit(0); }
55 
56 int main(int argc, char const *argv[]) 
57 {
58   freopen("nanjolno.in", "r", stdin);
59   freopen("nanjolno.out", "w", stdout);
60 
61   int u = 0, v = 0, ans = 0;
62   scanf("%d%d", &n, &p);
63   for(int i = 1; i <= p; ++i) buy[i] = read(), val[i] = read();
64   scanf("%d", &m);
65   for(int i = 1; i <= m; ++i) u = read(), v = read(), Add_edge(u, v);
66   for(int i = 1; i <= n; ++i) if( !dfn[i] ) Tarjan(i);
67 
68   // for(int i = 1; i <= n; ++i) printf("%d ", col[i]);
69   // printf("\n");
70 
71   memset(head, 0, sizeof head), edge_num = 0;
72   for(int i = 1; i <= m; ++i)
73     if( col[edge[i].u] != col[edge[i].v] )
74       Add_edge(col[edge[i].u], col[edge[i].v]), ++deg[edge[edge_num].v];
75 
76   // for(int i = 1; i <= col_num; ++i) printf("%d ", deg[i]);
77   // printf("\n");
78 
79   memset(cost, 0x3f, sizeof cost);
80   for(int i = 1; i <= p; ++i)
81     cost[col[buy[i]]] = min(cost[col[buy[i]]], val[i]);
82   for(int i = 1; i <= col_num; ++i)
83     if( !deg[i] ) Deep_fs(i, cost[i]), ans += cost[i];
84 
85   // for(int i = 1; i <= col_num; ++i) printf("%d ", cost[i]);
86   // printf("\n");
87 
88   for(int i = 1; i <= n; ++i) 
89     if( cost[col[i]] == 0x3f3f3f3f ) Failed(i);
90   printf("YES\n%d\n", ans);
91   
92   fclose(stdin), fclose(stdout);
93   return 0;
94 }

 劍的意義……會根據役劍之人而改變……  你要役劍……絕不能……為劍所役……  你要自由的活下去……絕不能被家名拘束……  什麽才是正確的……你必須,用你的雙眼去證實……

                      —— 黑羽《穢翼的尤斯蒂婭》

[Luogu 1262] 間諜網絡