题目描述
由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果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,并在第二行输出不能控制的间谍中,编号最小的间谍编号。
题解
首先想到如果是NO的话那么贿赂所有能贿赂的人都不能控制所有间谍,直接DFS
由于可能出现环,那么一个环里的所有间谍只需要贿赂一个最便宜的就好了,理所当然缩点
缩点之后就是一个DAG了,类似很多条链。对于同一条链上的间谍,显然dfs序先的点更优(显然),那么那些入度为0的点优先级就最高了。选上所有入度为0的点就是YES的花费
一道水题调n久也是醉了
Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#define debug puts("-----")
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define min(x, y) x<y?x:y
#define max(x, y) x>y?x:y
#define PI (acos(-1.0))
#define EPS (1e-8)
#define INF (1<<30)
#define ll long long
#define db double
#define ld long double
#define N 5001
#define E N * 8 + 1
#define L 255
using namespace std;
struct edge{int x, y, w, next;}e[E], g[E];
int ind[N], dfn[N], low[N], vis[N], lsE[N], lsG[N], edgeCntE, edgeCntG;
int totCost[N], inStack[N], memb[N], cost[N], comp[N], tot, cnt;
stack<int>s;
inline int read(){
int x = 0, v = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-'){
v = -1;
}
ch = getchar();
}
while (ch <= '9' && ch >= '0'){
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * v;
}
inline int addEdgeE(int x, int y, int w = 0){
e[++edgeCntE] = (edge){x, y, w, lsE[x]}; lsE[x] = edgeCntE;
return 0;
}
inline int addEdgeG(int x, int y, int w = 0){
g[++edgeCntG] = (edge){x, y, w, lsG[x]}; lsG[x] = edgeCntG;
return 0;
}
inline int dfs1(int now){
cnt += 1;
dfn[now] = low[now] = cnt;
inStack[now] = 1;
s.push(now);
for (int i = lsE[now]; i; i = e[i].next){
if (!dfn[e[i].y]){
dfs1(e[i].y);
low[now] = min(low[now], low[e[i].y]);
}else{
if (inStack[e[i].y]){
low[now] = min(low[now], dfn[e[i].y]);
}
}
}
if (dfn[now] == low[now]){
tot += 1;
for (int tmp = 0; tmp != now; ){
tmp = s.top(); s.pop();
comp[tmp] = tot;
inStack[tmp] = 0;
if (cost[tmp] != 0){
totCost[tot] = min(totCost[tot], cost[tmp]);
}
}
}
}
inline int tarjan(int n){
fill(totCost, 63);
fill(inStack, 0);
fill(dfn, 0);
fill(low, 0);
tot = cnt = 0;
rep(i, 1, n){
if (!dfn[i]){
dfs1(i);
}
}
}
inline int dfs2(int now){
vis[now] = 1;
for (int i = lsG[now]; i; i = g[i].next){
dfs2(g[i].y);
}
}
int main(void){
int n = read(), p = read();
edgeCntE = edgeCntG = 1;
rep(i, 1, p){
memb[i] = read();
cost[memb[i]] = read();
}
int m = read();
rep(i, 1, m){
int x = read(), y = read();
addEdgeE(x, y);
}
tarjan(n);
fill(ind, 0);
rep(i, 2, edgeCntE){
if (comp[e[i].x] != comp[e[i].y]){
addEdgeG(comp[e[i].x], comp[e[i].y]);
ind[comp[e[i].y]] += 1;
}
}
int ans = 0;
rep(i, 1, p){
if (!vis[comp[memb[i]]]){
dfs2(comp[memb[i]]);
}
}
rep(i, 1, n){
if (!vis[comp[i]]){
printf("NO\n%d\n", i);
return 0;
}
}
rep(i, 1, tot){
if (!ind[i]){
ans += totCost[i];
}
}
printf("YES\n%d\n", ans);
return 0;
}