【洛谷P1262】间谍网络
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }