poj 2553(3180) tarjan强连通分量(找图的“sink”点)

题意:2553:定义图的bottom集合为:bottom(G)={v∈V|∀w∈V:(v→w)⇒(w→v)}。

对于3180,谁能告诉我这个题是什么意思?看了别人的解答是求点数大于等于2的强连通分量的个数,可是为什么呢?

思路:依题意,所求即求出强连通分量缩点后出度为0的那些强连通分量中得点。用tarjan算法即可。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define clr(s,t) memset(s,t,sizeof(s))
#define N 5005
struct edge{
    int y,next;
}e[N*N];
int stack[N],first[N],dfn[N],low[N],instack[N],strong[N];
int n,m,top,id,st,con;
void init(){
    top = id = st = con = 0;
    clr(first,-1);
    clr(dfn,-1);
    clr(instack, 0);
}
int cmp(const void* a,const void* b){
    return (*(int*)a) - (*(int*)b);
}
void add(int x,int y){
    e[top].y = y;
    e[top].next = first[x];
    first[x] = top++;
}
void tarjan(int x){
    int i,y;
    dfn[x] = low[x] = ++id;
    stack[st++] = x;
    instack[x] = 1;
    for(i = first[x];i!=-1;i=e[i].next){
        y = e[i].y;
        if(dfn[y]==-1){
            tarjan(y);
            low[x] = min(low[x],low[y]);
        }else if(instack[y])
            low[x] = min(low[x],dfn[y]);
    }
    if(dfn[x] == low[x]){
        con ++;
        do{
            strong[stack[--st]] = con;
            instack[stack[st]] = 0;
        }while(stack[st] != x);
    }
}
int main(){
    while(scanf("%d",&n) && n){
        int a,b,i,j;
        init();
        scanf("%d",&m);
        for(i = 0;i<m;i++){
            scanf("%d %d",&a,&b);
            add(a,b);
        }
        for(i = 1;i<=n;i++)
            if(dfn[i] == -1)
                tarjan(i);
        
        clr(dfn, 0);
        for(i = 1;i<=n;i++)
            for(j = first[i];j!=-1;j=e[j].next)
                if(strong[i] != strong[e[j].y])
                    dfn[strong[i]] = 1;
        clr(first,0);
        for(top=0,i=1;i<=n;i++)
            if(!dfn[strong[i]])
                first[top++] = i;
        qsort(first,top,sizeof(int),cmp);
        for(i = 0;i<top;i++)
            printf("%d ",first[i]);
        putchar('\n');
    }
    return 0;
}

3180:

#include <stdio.h>
#include <string.h>
#define N 10005
#define INF 0x3fffffff
#define clr(s,t) memset(s,t,sizeof(s))
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
struct edge{
    int y,next;
}e[50005];
int dfn[N],low[N],first[N],stack[N],inst[N];
int n,m,id,top,con,st,res;
void init(){
    top = id = con = st = res = 0;
    clr(first, -1);
    clr(dfn, -1);
    clr(inst, 0);
}
void add(int x,int y){
    e[top].y = y;
    e[top].next = first[x];
    first[x] = top++;
}
void tarjan(int x){
    int i,y,num=0;
    dfn[x] = low[x] = ++id;
    stack[st++] = x;
    inst[x] = 1;
    for(i = first[x];i!=-1;i=e[i].next){
        y = e[i].y;
        if(dfn[y] == -1){
            tarjan(y);
            low[x] = min(low[x], low[y]);
        }else if(inst[y])
            low[x] = min(low[x], dfn[y]);
    }
    
    if(dfn[x] == low[x]){
        con++;
        do{
            --st;
            inst[stack[st]] = 0;
            num++;
        }while(x != stack[st]);
        if(num >= 2)
            res++;
    }
}int main(){
    while(scanf("%d %d",&n,&m) != EOF){
        int i,a,b;
        init();
        for(i = 0;i<m;i++){
            scanf("%d %d",&a,&b);
            add(a,b);
        }
        for(i = 1;i<=n;i++)
            if(dfn[i] == -1)
                tarjan(i);
        printf("%d\n",res);
    }
    return 0;
}


你可能感兴趣的:(poj 2553(3180) tarjan强连通分量(找图的“sink”点))