码迷,mamicode.com
首页 > 其他好文 > 详细

模板 - 强连通分量

时间:2019-08-13 15:48:50      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:==   org   不能   typedef   end   ref   name   else   ems   

技术图片

Kosaraju算法 O(n+m)

vector<int> s;

void dfs1(int u) {
    vis[u] = true;
    for (int v : g[u])
        if (!vis[v])
            dfs1(v);
    s.push_back(v);
}

void dfs2(int u) {
    color[u] = sccCnt;
    for (int v : g2[u])
        if (!color[v])
            dfs2(v);
}

void Kosaraju() {
    s.clear();
    for (int i = 1; i <= n; ++i)
        if (!vis[i])
            dfs1(i);
    sccCnt = 0;
    for (int i = n; i >= 1; --i)
        if (!color[s[i]]) {
            ++sccCnt;
            dfs2(s[i])
        }
}

https://www.luogu.org/problem/P1262
首先考虑假如一个间谍没办法被揭发不能被贿赂,也就是他不是可行的入口点也没有别人指向他,那么无解。
否则可能要若干个入度为0的点,这些点必须被贿赂,且这些点能到达的点不需要再贿赂。
否则一定存在环,或者多个环交在一起的,而这些环都是同一强连通分量内的,找这个强连通分量里面的最小的那个。

有个问题就是加入强连通分量里的都不能被贿赂就很尴尬了,所以干脆一开始就把强连通分量用编号最小的点来代替?

这个就是在dfs1的时候把额外的信息维护好了,然后在dfs2的时候维护这个强连通分量的最小花费以及假如是INF的话的最小id。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 3005;
const int INF = 0x3f3f3f3f;

int n,w[MAXN], indeg[MAXN];

vector<int> G[MAXN], G2[MAXN];

//从i点出发的连通分量,染色为c1[i]
int c1[MAXN],cntc1;
bool visc1[MAXN];

//i点所在的强连通分量,染色为c2[i]
int c2[MAXN],cntc2;
int minCost[MAXN], minID[MAXN];

int s[MAXN],cnts;

void dfs1(int u,int c) {
    c1[u]=c;
    for (int v : G[u]) {
        if (!c1[v])
            dfs1(v,c);
        s[++cnts]=v;
    }
}


void dfs2(int u, int &minid) {
    c2[u] = cntc2;
    minCost[cntc2] = min(minCost[cntc2], w[u]);
    minid = min(minid, minID[cntc2]);
    for (int v : G2[u])
        if (!c2[v])
            dfs2(v, minid);
}

void Kosaraju(ll &sum, int &minid) {
    minid = INF;
    for (int i = 1; i <= n; ++i)
        if (!c1[i]){
            ++cntc1;
            dfs1(i,cntc1);
        }
    for (int i = n; i >= 1; --i) {
        if (!c2[s[i]]) {
            ++cntc2;
            minCost[cntc2] = INF;
            minID[cntc2] = INF;
            dfs2(s[i], minid);
        }
        if(minCost[cntc2] == INF)
            minid = min(minid, minID[cntc2]);
        else{
            if(!visc1[c1[s[i]]]){
                visc1[c1[s[i]]]=true;
                sum += minCost[cntc2];
            }
        }
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int p;
    scanf("%d%d", &n, &p);
    memset(w, INF, sizeof(w[0]) * (n + 1));
    for(int i = 1; i <= p; ++i) {
        int id, c;
        scanf("%d%d", &id, &c);
        w[id] = c;
    }
    int m;
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        ++indeg[v];
        G[u].emplace_back(v);
        G2[v].emplace_back(u);
    }
    ll sum = 0;
    for(int i = 1; i <= n; ++i) {
        if(indeg[i] == 0 && w[i] == INF) {
            puts("NO");
            printf("%d\n", i);
            return 0;
        } else if(indeg[i] == 0) {
            //处理了所有入度为0的点,剩下的必定是独立环
            ++cntc1;
            dfs1(i,cntc1);
            visc1[cntc1]=true;
            sum += w[i];
        }
    }
    int minid;
    Kosaraju(sum, minid);
    if(minid == INF) {
        puts("YES");
        printf("%lld\n", sum);
    } else {
        //某个强连通分量里有不能被贿赂的点
        puts("NO");
        printf("%d\n", minid);
    }
    return 0;
}

模板 - 强连通分量

标签:==   org   不能   typedef   end   ref   name   else   ems   

原文地址:https://www.cnblogs.com/Yinku/p/11345771.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!