• [Luogu 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,并在第二行输出不能控制的间谍中,编号最小的间谍编号。

    输入输出样例

    输入样例#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
    %d
    ", 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("
    ");
    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("
    ");
    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("
    ");
    87 
    88   for(int i = 1; i <= n; ++i) 
    89     if( cost[col[i]] == 0x3f3f3f3f ) Failed(i);
    90   printf("YES
    %d
    ", ans);
    91   
    92   fclose(stdin), fclose(stdout);
    93   return 0;
    94 }
     剑的意义……会根据役剑之人而改变……
     你要役剑……绝不能……为剑所役……
     你要自由的活下去……绝不能被家名拘束……
     什么才是正确的……你必须,用你的双眼去证实……

                          —— 黑羽《秽翼的尤斯蒂娅》

  • 相关阅读:
    Java垃圾收集器概述
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    Serialize a Long as a String
    数据库遇到的问题
    解决Safari页面缓存的问题
    idea -> Error during artifact deployment. See server log for details.
    正则表达式
    commons-lang
    Template和Style
    WPF资源
  • 原文地址:https://www.cnblogs.com/nanjoqin/p/9472315.html
Copyright © 2020-2023  润新知