poj 1236 Network (SCC缩点)

题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

考虑问题1:对于每个强连通分量最多需发放1个,再看其与其他强连通分量,如果强连通分量A与B,A->B可以传输,则只需在A发放软件。于是,求出强连通分量并进行缩点后,统计一下入度为0的点个数就是答案。

考虑问题2:问题的本质就是添加尽量少的边使得新图强连通。由于缩点后得到的是DAG图(两点之间最多只有1条边),于是只需求出统计点的入度和出度取最大值就是答案。注意原图本身就是强连通的情况就好了。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
using namespace std;
#define N 105
vector<int> G[N];
int pre[N],low[N],sccno[N],dfs_clock,scc_cnt,cnt[N];
stack<int>S;
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]){
        cnt[++scc_cnt]=0;
        for(;;){
            int x=S.top();S.pop();
            sccno[x]=scc_cnt;
            ++cnt[scc_cnt];
            if(x==u) break;
        }
    }
}
void find_scc(int n){
    dfs_clock=scc_cnt=0;
    memset(sccno,0,sizeof(sccno));
    memset(pre,0,sizeof(pre));
    for(int i=0;i<n;++i) if(!pre[i]) dfs(i);
}
int in[N],out[N];
int main()
{
    int i,j,n,x;
    while(~scanf("%d",&n))
    {
        for(i=0;i<n;++i){
            G[i].clear();
            while(~scanf("%d",&x)&&x) G[i].push_back(--x);
        }
        find_scc(n);
        if(scc_cnt==1) {printf("1\n0\n");continue;}
        for(i=1;i<=scc_cnt;++i) in[i]=out[i]=0;
        for(i=0;i<n;++i)
        for(j=0;j<G[i].size();++j){
            int v=G[i][j];
            if(sccno[v]!=sccno[i]) {++in[sccno[v]];++out[sccno[i]];}
        }
        int ans1=0,ans2=0;
        for(i=1;i<=scc_cnt;++i)
        {
            if(!in[i]) ++ans1;
            if(!out[i]) ++ans2;
        }
        printf("%d\n%d\n",ans1,max(ans1,ans2));
    }
    return 0;
}


你可能感兴趣的:(poj 1236 Network (SCC缩点))