【洛谷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

#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;
}
AC Code

猜你喜欢

转载自www.cnblogs.com/-sheldon/p/11403635.html
今日推荐