poj 1236 Network of Schools(强连通分量构造强连通图)

题目:http://poj.org/problem?id=1236
题意:

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

分析:

先找出强连通分量,缩点,得到一个DAG。对于问题1,显然只要一个点有入度,那么就可以传进来,所以找入度为0的点的个数即可。对于问题2,相当于在加多少条边,可以得到强连通图?答案就是max{ 入度为0的点数,出度为0的点数 },为什么?因为一个点必须有入度和出度。

代码:

using namespace std;

const int N = 100 + 10;
vector<int> G[N];
int pre[N], lowlink[N], sccno[N], dfs_clock, scc_cnt;
stack<int> S;

void dfs(int u) {
    pre[u] = lowlink[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);
            lowlink[u] = min(lowlink[u], lowlink[v]);
        } else if(!sccno[v]) {
            lowlink[u] = min(lowlink[u], pre[v]);
        }
    }
    if(lowlink[u] == pre[u]) {
        ++scc_cnt;
        int x;
        do {
            x = S.top();
            S.pop();
            sccno[x] = scc_cnt;
        } while(x!=u);
    }
}

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 in0[N], out0[N];

int main() {
    int  n, m,x;
    //freopen("f.txt","r",stdin);
    scanf("%d", &n);
    for(int i = 0; i < n; i++) G[i].clear();
    for(int i = 0; i < n; i++) {
        while(scanf("%d",&x)&&x) {
            G[i].push_back(x-1);
        }
    }
    find_scc(n);

    for(int i = 1; i <= scc_cnt; i++) in0[i] = out0[i] = 1;
    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]] = 0;
        }
    int a = 0, b = 0;
    for(int i = 1; i <= scc_cnt; i++) {
        if(in0[i]) a++;
        if(out0[i]) b++;
    }
    int ans = max(a, b);
    if(scc_cnt == 1) ans = 0;
    printf("%d\n%d\n", a,ans);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值