• [Luogu] P1262 间谍网络


    (Link)

    Description

    由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果(A)间谍手中掌握着关于(B)间谍的犯罪证据,则称(A)可以揭发(B)。有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报。所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子。因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报。

    我们的反间谍机关提供了一份资料,包括所有已知的受贿的间谍,以及他们愿意收受的具体数额。同时我们还知道哪些间谍手中具体掌握了哪些间谍的资料。假设总共有(n)个间谍((n)不超过(3000)),每个间谍分别用(1)(3000)的整数来标识。

    请根据这份资料,判断我们是否有可能控制全部的间谍,如果可以,求出我们所需要支付的最少资金。否则,输出不能被控制的一个间谍。

    Solution

    还是有一些东西要考虑的。

    首先肯定要跑一遍缩点,然后在同一强连通分量内的间谍就只要收买一个了。那么我们肯定是要把所有入度为零的点(缩点后)买掉,如果这一强连通分量内的所有间谍都不能被收买,那么就不能收买所有间谍,输出这个强连通分量内的最小间谍编号。否则我们肯定是收买入度为零的点中金额最小的那个间谍。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int n, m, p, tot, top, ind, cnt, fl = 1, id, sum, mnid[3005], mn[3005], col[3005], ok[3005], money[3005], rd[3005], hd[3005], to[8005], nxt[8005], dfn[3005], low[3005], que[3005], vis[3005];
    
    int read()
    {
    	int x = 0, fl = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    	return x * fl;
    }
    
    void add(int u, int v)
    {
    	tot ++ ;
    	to[tot] = v;
    	nxt[tot] = hd[u];
    	hd[u] = tot;
    	return;
    }
    
    void dfs(int x)
    {
    	low[x] = dfn[x] = ++ ind;
    	que[ ++ top] = x;
    	vis[x] = 1;
    	for (int i = hd[x]; i; i = nxt[i])
    	{
    		int y = to[i];
    		if (!dfn[y])
    		{
    			dfs(y);
    			low[x] = min(low[x], low[y]);
    		}
    		else if (vis[y]) low[x] = min(low[x], dfn[y]);
    	}
    	if (low[x] == dfn[x])
    	{
    		cnt ++ ;
    		int now = -1;
    		do
    		{
    			now = que[top --];
    			col[now] = cnt;
    			if (money[now]) mn[cnt] = min(mn[cnt], money[now]);
    			ok[cnt] |= money[now];
    			mnid[cnt] = min(mnid[cnt], now);
    			vis[now] = 0;
    		} while (now != x);
    	}
    	return;
    }
    
    int main()
    {
    	n = read(); p = read();
    	for (int i = 1; i <= p; i ++ )
    	{
    		int x = read();
    		money[x] = read();
    	}
    	m = read();
    	for (int i = 1; i <= m; i ++ )
    	{
    		int u = read(), v = read();
    		add(u, v);
    	}
    	memset(mn, 0x3f, sizeof(mn));
    	memset(mnid, 0x3f, sizeof(mnid));
    	for (int i = 1; i <= n; i ++ )
    		if (!dfn[i])
    			dfs(i);
    	for (int x = 1; x <= n; x ++ )
    	{
    		for (int i = hd[x]; i; i = nxt[i])
    		{
    			int y = to[i];
    			if (col[y] != col[x]) rd[col[y]] ++ ;		
    		}
    	}
    	for (int i = 1; i <= cnt; i ++ )
    	{
    		if (!rd[i])
    		{
    			if (!ok[i])
    			{
    				fl = 0;
    				id = mnid[i];
    				break;
    			}
    			else sum += mn[i];
    		}
    	}
    	if (fl)
    	{
    		puts("YES");
    		printf("%d
    ", sum);
    	}
    	else
    	{
    		puts("NO");
    		printf("%d
    ", id);
    	}
    	return 0;	
    }
    
  • 相关阅读:
    java 多线程
    数据结构与算法-----快速排序
    JS 强制类型转化
    VS Code 编辑器
    MySQL8数据库安装配置和启动
    listview更改选中时item背景色(转)
    Android下用程序的方法为ListView设置分割线Divider样式
    listview android:cacheColorHint,android:listSelector属性作用
    Android手动显示和隐藏软键盘
    android调试debug快捷键
  • 原文地址:https://www.cnblogs.com/andysj/p/13913995.html
Copyright © 2020-2023  润新知