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;
}

猜你喜欢

转载自blog.csdn.net/lanshan1111/article/details/84951678
今日推荐