间谍网络

洛谷题目链接
loj题目链接

tarjan求强联通分量,每个强联通分量内的间谍可以互相揭发,缩点

跑拓扑排序,每个间谍(强连通分量)只可能被拓扑排序比他小的揭发

扫一遍,没被控制的收买一下,收买不了输出no.(代码实现的时候有些区别,这样也是对的)

#include <bits/stdc++.h>
using namespace std;
int low[5000], color[5000], cnt = 0, w[5000], uu[50000], vv[50000], cover[5000], rd[5000], line[5000], lc = 0,
                             ww[5000], colornum = 0, dfn[5000], t = 0, sta[5000], stac = 0,
                            in[5000], head[5000];
struct node {
    int to, nxt;
} road[10000];
void build(int u, int v) 
{
    road[++cnt].to = v;
    road[cnt].nxt = head[u];
    head[u] = cnt;
}
void tarjan(int u) 
{
    low[u] = dfn[u] = ++t;
    in[u] = 1, sta[++stac] = u;
    for (int i = head[u]; i; i = road[i].nxt) 
	{
        int v = road[i].to;
        if (!dfn[v]) 
		{
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (in[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) 
	{
        color[u] = ++colornum, in[u] = 0;
        if (w[u] != -1)
            ww[colornum] = w[u];
        while (sta[stac] != u) 
		{
            in[sta[stac]] = 0;
            if (w[sta[stac]] != -1) 
			{
                if (ww[colornum] == -1)
                    ww[colornum] = w[sta[stac]];  // QAQ
                else
                    ww[colornum] = min(ww[colornum], w[sta[stac]]);
            }
            color[sta[stac]] = colornum;
            stac--;
        }
        stac--;
    }
}
int ans = 0;
void tuopu(int u) {
    line[++lc] = u;
    for (int i = head[u]; i; i = road[i].nxt) {
        int v = road[i].to;
        rd[v]--;
        if (!rd[v])
            tuopu(v);
    }
}
void dfs(int u) {
    cover[u] = 1;
    for (int i = head[u]; i; i = road[i].nxt) {
        int v = road[i].to;
        if (!cover[v])
            dfs(v);
    }
}
int main() {
    memset(w, -1, sizeof(w));
    memset(ww, -1, sizeof(ww));
    int n, p, r, u, v, ans = 0;
    cin >> n >> p;
    for (int i = 1; i <= p; i++) {
        int x;
        cin >> x;
        cin >> w[x];
    }
    cin >> r;
    for (int i = 1; i <= r; i++) {
        cin >> uu[i] >> vv[i];
        build(uu[i], vv[i]);
    }
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) {
            tarjan(i);
        }
    }
    memset(head, 0, sizeof(head));
    cnt = 0;
    for (int i = 1; i <= r; i++) {
        if (color[uu[i]] != color[vv[i]]) {
            build(color[uu[i]], color[vv[i]]);
            rd[color[vv[i]]]++;
        }
    }
    for (int i = 1; i <= colornum; i++) {
        if (!rd[i])
            tuopu(i);
    }
    for (int i = 1; i <= lc; i++) {
        if (!cover[line[i]] && ww[line[i]] != -1) {
            ans += ww[line[i]];
            dfs(line[i]);
        } 
    }
    int f = 0;
    for (int i = 1; i <= n; i++) //直接循环强联通分量 不能保证编号最小 
	// 循环的顺序是按编号从小到大,但是实际最先成为强联通分量,可能是编号较大的某个儿子
	{
        if (!cover[color[i]]) {
            f = 1;
            cout << "NO"<<"
"<< i;
            break;  // QAQ
        }
    }
    if (f == 0)
        cout << "YES"
             << "
"
             << ans;
    return 0;
}
原文地址:https://www.cnblogs.com/qwq-/p/13632636.html