增加最少的边使有向图变为强连通图

http://codeforces.com/contest/22/problem/E

标题党。。。

此题是这个问题的简化版本,每个点出度至多为一。先强连通缩点,每个点出度至多为一可以保证从任一个入度为0的点出发只能到达一个出度为0的点按标号从第一个入度为0的点a开始,找到其对应的出度为0的点(缩后)a',再找到第二个入度为0的点b,连边a'->b,...,直到最后一个出度为0的点z‘,连边z’->a,后形成一个“环”。由于图的特殊性,可以保证所有的出度为0的点(缩后)都连了出边,这个"环"上就包含了所有出度 入度为0的点,不难看出,这是强连通图。

至于一般的有向图还没想到好方法。


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <stack>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

const int MAXN(100010);
const int MAXE(100010);
template<typename T>
bool checkmin(T &a, const T &b){
    return b < a? (a = b, true): false;
}
template<typename T>
bool checkmax(T &a, const T &b){
    return b > a? (a = b, true): false;
}

inline int lowb(int i){return i&-i;}
int gcd(int a, int b){
    while(b){
        int t = a%b;
        a = b;
        b = t;
    }
    return a;
}

struct E{
    int u, v;
    E *next;
};

struct G{
    E *h[MAXN];
    E e[MAXE], *r;
    void init(int n){
        memset(h, 0, sizeof(h[0])*(n+1));
        r = e;
    }
    void add(int u, int v){
        r->u = u;
        r->v = v;
        r->next = h[u];
        h[u] = r++;
    }
} g, g1, g2, g3;
stack<int> st;
int co[MAXN], rep[MAXN], to[MAXN], ind[MAXN], out[MAXN], cn;
bool vis[MAXN];

void dfs(int u){
    vis[u] = true;
    for(E *i = g.h[u]; i; i = i->next)
        if(!vis[i->v])
            dfs(i->v);
    st.push(u);
}

void dfs1(int u){
    co[u] = cn;
    for(E *i = g1.h[u]; i; i = i->next)
        if(!co[i->v])
            dfs1(i->v);
}

void dfs2(int u, int rt){
    vis[u] = true;
    bool leaf(true);
    for(E *i = g2.h[u]; i; i = i->next){
        leaf = false;
        if(!vis[i->v]) dfs2(i->v, rt);
    }
    if(leaf) to[u] = rt;
}

int main(){
    int n, u;
    scanf("%d", &n);
    g.init(n);
    g1.init(n);
    for(int i = 1; i <= n; ++i){
        scanf("%d", &u);
        g.add(i, u);
        g1.add(u, i);
    }
    for(int i = 1; i <= n; ++i)
        if(!vis[i])
            dfs(i);
    while(!st.empty()){
        u = st.top();
        st.pop();
        if(co[u]) continue;
        co[u] = ++cn;
        rep[cn] = u;
        dfs1(u);
    }
    if(cn == 1){
        printf("0\n");
        return 0;
    }
    g2.init(cn);
    memset(ind, 0, sizeof(ind[0])*(cn+1));
    for(E *i = g.e; i < g.r; ++i)
        if(co[i->u] != co[i->v]){
            g2.add(co[i->v], co[i->u]);
            ++out[co[i->u]];
            ++ind[co[i->v]];
        }
    memset(vis, 0, sizeof(vis[0])*(cn+1));
    for(int i = 1; i <= cn; ++i)
        if(out[i] == 0)
            dfs2(i, i);
    int ans = 0, f = 0;
    for(int i = 1; i <= cn; ++i)
        if(ind[i] == 0){
            if(!f) f = i;
            ++ans;
        }
    printf("%d\n", ans);
    int l = f;
    for(int i = f+1; i <= cn; ++i)
        if(ind[i] == 0){
            printf("%d %d\n", rep[to[l]], rep[i]);
            l = i;
        }
    printf("%d %d\n", rep[to[l]], rep[f]);
    return 0;
}


你可能感兴趣的:(增加最少的边使有向图变为强连通图)