1. 程式人生 > >POJ 1236Network of Schools強聯通分量

POJ 1236Network of Schools強聯通分量

http://poj.org/problem?id=1236

//看強聯通分量

在有向無環圖中,邊變為了強連通分量之間的檔案傳輸關係。意味這:只要一個強連通分量有入

邊,那麼就可以通過這個入邊從另外一個分量中接收檔案。但是,無環圖意味著肯定存在沒有入

度(入度為0)的強連通分量,這些強連通分量沒有檔案來源,所以要作為投放檔案的位置。那麼,

第一問就只需要計算出縮點後入度為0的強連通分量數目即可。

而第二個問題,把一個有向無環圖轉換為一個強連通分量。強連通分量的主要特徵是:每個點的

入度和出度都不為0,那麼計算出入度為0的點的個數SumIn和出度為0的點的個數SumOut,題

目就變為了:在入度為0的點和出出度為0的點之間最少加多少邊。很明顯的可以看出,答案就是

max(SumIn,SumOut)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=105;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n;
struct edge{
    int v,ne;
}e[N*N];
int h[N],cnt=0;
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
}

int dfn[N],low[N],belong[N],dfc,scc;
int st[N],top=0;
void dfs(int u){
    dfn[u]=low[u]=++dfc;
    st[++top]=u;
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(!dfn[v]){
            dfs(v);
            low[u]=min(low[u],low[v]);
        }else if(!belong[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        scc++;
        while(true){
            int x=st[top--];
            belong[x]=scc;
            if(x==u) break;
        }
    }
}
int outd[N],ind[N];
void point(){
    for(int u=1;u<=n;u++)
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(belong[u]!=belong[v]) outd[belong[u]]++,ind[belong[v]]++;
        }
}
int main(){
    n=read();
    for(int u=1;u<=n;u++){
        int v=read();
        while(v!=0){ins(u,v);v=read();}
    }
    for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
    point();
    int cnt1=0,cnt2=0;
    for(int i=1;i<=scc;i++){
        if(ind[i]==0) cnt1++;
        if(outd[i]==0) cnt2++;
    }
    if(scc==1) printf("1\n0");
    else printf("%d\n%d",cnt1,max(cnt1,cnt2));
}

 

 

#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=100+10;
int n,m;
vector<int> G[maxn];
stack<int> S;
int dfs_clock, scc_cnt;
int pre[maxn],low[maxn],sccno[maxn];
int in0[maxn],out0[maxn];
void dfs(int u)
{
    pre[u]=low[u]=++dfs_clock;
    S.push(u);
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(!pre[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v])
            low[u]=min(low[u],pre[v]);
    }
    if(low[u]==pre[u])
    {
        scc_cnt++;
        while(true)
        {
            int x=S.top(); S.pop();
            sccno[x]=scc_cnt;
            if(x==u) break;
        }
    }
}
void find_scc(int n)
{
    dfs_clock=scc_cnt=0;
    memset(pre,0,sizeof(pre));
    memset(sccno,0,sizeof(sccno));
    for(int i=0;i<n;i++)
        if(!pre[i]) dfs(i);
}
int main()
{
    while(scanf("%d",&n)==1&&n)
    {
        for(int i=0;i<n;i++) G[i].clear();
        for(int u=0;u<n;u++)
        {
            int v;
            while(scanf("%d",&v)==1&&v)
            {
                v--;
                G[u].push_back(v);
            }
        }//從0開始編號;
        find_scc(n);//進行演算法,求強連通分量;
        for(int i=1;i<=scc_cnt;i++)
            in0[i]=out0[i]=true;//目前初始化為true;
        for(int u=0;u<n;u++)
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(sccno[u]!=sccno[v])
                in0[sccno[v]]=out0[sccno[u]]=false;
                //如果不屬於一個強連通分量;a->b
                //剩餘為true的就是強連通分量所在點;
                //兩個聯通分量包含元素個數不同,不為一個強連通分量;
        }
        int a=0, b=0;
        for(int i=1;i<=scc_cnt;i++)
        {
            if(in0[i]) a++;//入度為0為強連通分量個數;
            if(out0[i]) b++;//出度為0
        }
        if(scc_cnt==1) printf("1\n0\n");//只有一個強連通分量;
        else printf("%d\n%d\n",a,max(a,b));//
    }
    return 0;
}