pku1236 Network of Schools

求强连通分量的基础题,用来练一下刚搞懂的Tarjan:

Tarjan算法的过程就是不断避免把桥纳入强连通分量中

注意到以下性质:
1,桥一定是DFS树中的边
2,一条树边v-w为桥,当且仅当不存在回边将w的一个子孙与w的一个祖先相连

 

#include <iostream>
#include 
<stack>
using namespace std;

#define Max(a,b)(a<b?b:a)
#define MAXN 101

int p[MAXN],ecnt,n,c,ideg[MAXN],odeg[MAXN];
int lowlink[MAXN],//结点所处强连通分量的代表结点,也是具有最小时间截的结点(在DFS树中深度最浅)(动态更新)
    dfn[MAXN],//访问时间(固定)
    sign,//时间截
    SCC[MAXN];//结点所处强连通分量
bool visited[MAXN],instack[MAXN];
stack
<int> st;

struct Edge{
    
int v,next;
}edg[
10000];

void update(int &a,int b){
    a
=(a<b?a:b);
}

void dfs(int u){
    
int i,v;
    st.push(u);
    visited[u]
=instack[u]=true;
    lowlink[u]
=dfn[u]=++sign;
    
for(i=p[u];i!=-1;i=edg[i].next){
        v
=edg[i].v;
        
if(visited[v]){
            
if(instack[v]){
                update(lowlink[u],bfn[v]);
//u-v是返祖边
            }
        }
        
else{
            dfs(v);
            update(lowlink[u],lowlink[v]);
        }
    }
    
if(lowlink[u]==dfn[u]){//若u是代表结点,则深度比其深的仍在栈内的待处理结点均属于该强连通分量
        c++;
        
do{
            v
=st.top();
            st.pop();
            instack[v]
=false;
            SCC[v]
=c;
        }
while(v!=u);
    }
}

void Tarjan(){
    
int i;
    c
=0;
    sign
=0;
    memset(visited,
false,sizeof(visited));
    memset(instack,
false,sizeof(instack));
    
for(i=1;i<=n;i++)
        
if(!visited[i])
            dfs(i);
}

void solve(){
    
int i,u,v,ic,oc;

    Tarjan();
//求强连通分量
    

    memset(ideg,
0,sizeof(ideg));
    memset(odeg,
0,sizeof(odeg));
    
for(u=1;u<=n;u++){
        
for(i=p[u];i!=-1;i=edg[i].next){
            v
=edg[i].v;
            
if(SCC[u]!=SCC[v]){
                odeg[SCC[u]]
++;
                ideg[SCC[v]]
++;
            }
        }
    }

    
if(c==1){
        printf(
"1\n0\n");
        
return;
    }


    ic
=oc=0;
    
for(i=1;i<=c;i++){
        
if(ideg[i]==0)
            ic
++;
        
if(odeg[i]==0)
            oc
++;
    }
    printf(
"%d\n%d\n",ic,Max(ic,oc));
}


int main(){
    
int u,v;
    
while(scanf("%d",&n)!=EOF){
        
while(!st.empty())
            st.pop();
        ecnt
=0;
        memset(p,
-1,sizeof(p));
        
for(u=1;u<=n;u++){
            
while(scanf("%d",&v) && v){
                edg[ecnt].v
=v;
                edg[ecnt].next
=p[u];
                p[u]
=ecnt++;
            }
        }
        solve();
    }
    
return 0;
}
posted @ 2009-01-18 17:41  Beetlebum  阅读(507)  评论(0编辑  收藏  举报