Description
给定n个点 其中p个点可以被贿赂, 被贿赂的金额为x,如果一个点被贿赂,他所指向的点也会被贿赂
求:如果不能全部被贿赂 输出NO以及不能被贿赂的点 否则输出YES和需要支付的金额的最小值
Solution
我们可以通过tarjan缩点,最后扫一遍dfn,若果有一个点并没有被访问过,说明这个点肯定不会被贿赂 直接输出并结束程序
那么如果全部可以贿赂呢?我们想,一个强联通分量里面随便贿赂一个点,其他的全部都会被贿赂 那么我们是不是只在需要在进行tarjan的时候进行比较,求出最小值即可
然而
如果一个强联通分量指向另一个强联通分量,我们就可以用指向另一个的强联通分量里的最小值就可以了
有同学问:如果被指向的强联通分量里面有一个比指向的最小值还小的值,是不是可以用呢?
答案是不可以的 如果选择了指向的强联通分量,我们的花费是x,此时因为他指向另一个强联通分量,所以另一个不需要花钱,所以我们只需要统计入度为0的强联通分量,并且累加答案就可以了
注意:在进行tarjan的时候while(stack[top]! = u)前面后面都要有一个更新答案 因为有2中种特殊情况:u在栈顶和栈尾,当然你也可以不这么写,直接将top+1即可while(stack[top + 1] != u)
Code

#include <bits/stdc++.h>
const int INF = 1e9 + 10;
using namespace std;
int n, p, r, num, top, col, sh;
int mon[3010], coin[3010], head[10010], dfn[3010];
int st[3010], co[3010], low[3010], si[3010], vis[3010];
int ans[3010], ru[3010];
struct emmm {
int next, to;
}e[10010];
void tarjan(int u) {
st[++top] = u;
dfn[u] = low[u] = ++sh;
vis[u] = 1;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (!co[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
co[u] = ++col;
si[col]++;
ans[col] = min(ans[col], mon[st[top]]);
while (st[top] != u) {
si[col]++;
co[st[top]] = col;
vis[st[top]] = 0;
ans[col] = min(ans[col], mon[st[top]]);
top--;
}
ans[col] = min(ans[col], mon[st[top]]);
top--;
}
return ;
}
void add(int from, int to) {
e[++num].next = head[from];
e[num].to = to;
head[from] = num;
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> p;
for (int i = 1;i <= n; i++)
mon[i] = INF;
for (int i = 1;i <= n; i++)
ans[i] = INF - 110;
for (int i = 1;i <= p; i++){
int u, m;
cin >> u >> m;
mon[u] = m;
}
cin >> r;
for (int i = 1;i <= r; i++) {
int a, b;
cin >> a >> b;
add(a, b);
}
for (int i = 1;i <= n; i++)
if (!dfn[i] && mon[i] != INF)
tarjan(i);
for (int i = 1;i <= n; i++)
if (!dfn[i]) {
cout << "NO" <<endl << i << endl;
return 0;
}
for (int i = 1;i <= n; i++)
for (int j = head[i]; j; j = e[j].next)
if (co[i] != co[e[j].to])
ru[co[e[j].to]]++;
int anss = 0;
for (int i = 1;i <= col; i++)
if (!ru[i])
anss+=ans[i];
cout << "YES" << endl << anss << endl;
return 0;
}
