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;
}