LouZhang

导航

hdu_2767,加边至强连通

http://acm.hdu.edu.cn/showproblem.php?pid=2767

今天在做图论专题的时候碰到了这题,这样的话,正好学习了来写篇博客吧

题目意思就是,给你一个有向网络图,问,至少加多少条边能使这个图成强连通

那么就是要,先把图跑一遍targan,如果这个图是强连通,那么就输出0了,否则缩点,然后求所有点入度为0和出度为0个数的最大值了

主要理解的地方就是缩点的那个地方,要理解belong数组的含义,以及为什么是求入度0和出席0的最大值

证明我是不知道= =,真的是只能意会么 ?

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn(55555);
int low[maxn], dfn[maxn], vis[maxn], belong[maxn];
struct Edge{
    int v, next;
}e[maxn];
int head[maxn], cnt;
int n, m;
int step, color;
int stack[maxn], top;
void targan(int u){
    low[u] = dfn[u] = ++ step;
    vis[u] = 1;
    stack[top++] = u;
    for(int i = head[u]; i + 1; i = e[i].next){
        int v = e[i].v;
        //printf("--  %d %d\n", u, v);
        if(!dfn[v]){
            targan(v);
            low[u] = min(low[u], low[v]);
        }else if(vis[v])
          low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u]){
        color ++;
        int s;
        do{
            s = stack[--top];
            vis[s] = 0;
            belong[s] = color;
        }while(u != s);
    }
}
int in[maxn], out[maxn];
#define clr(a) memset(a, 0, sizeof a)
void init(){
    clr(dfn);
    clr(vis);
    clr(low);
    clr(belong);
    clr(in);
    clr(out);
    top = step = color = cnt = 0;
    memset(head, -1, sizeof head);
}
void add_Edge(int u, int v){
    e[cnt].v = v, e[cnt].next = head[u];
    head[u] = cnt ++;
}
void solve(){
    for(int i = 1; i <= n; i ++) if(!dfn[i]) targan(i);
    if(color == 1){
        puts("0");
        return;
    }
    for(int i = 1; i <= n; i ++){
        for(int j = head[i]; j + 1; j = e[j].next){
            int v = e[j].v;
            if(belong[i] != belong[v]){
                in[belong[v]]++;
                out[belong[i]] ++;
            }
        }
    }
    int a = 0, b = 0;
    for(int i = 1; i <= color; i ++){
        if(in[i] == 0) a ++;
        if(out[i] == 0) b ++;
    }
    printf("%d\n", max(a, b));
}
int main(){
    int tcase;
    scanf("%d", &tcase);
    while(tcase --){
        scanf("%d%d", &n, &m);
        if(m == 0){
            printf("%d\n", n);
            continue;
        }
        init();
        while(m--){
            int u, v;
            scanf("%d%d", &u, &v);
            add_Edge(u, v);
        }
        solve();
    }
    return 0;
}

posted on 2012-08-19 12:40  louzhang_swk  阅读(774)  评论(0编辑  收藏  举报