POJ1236 Network of Schools

gate

用时:大概60min
睡前随便水一发博客,摸了

有向图,一个点向其他点连边(传递信息)。
问:1.至少选多少点作为源点,使所有点都能收到信息。2.至少连多少边,使任选一点作为源点,都能使所有点收到消息。
显然每个强联通分量内的点可以互相到达,所以先缩点。
1的答案即为入度为0的点的个数。
2即要使每一点都有入度和出度,答案为入度和出度为0的点的较大值。
注意特判强连通图的情况,因为至少要选一个点。输入1,0即可。

代码如下

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#define Mogeko qwq
using namespace std;

const int maxn = 1e5+10;
int n,m,x[maxn],y[maxn],inn[maxn],out[maxn],ans1,ans2;
int head[maxn],to[maxn],nxt[maxn],cnt;
int dfn[maxn],low[maxn],sta[maxn],col[maxn],top,now,num;
bool insta[maxn];

int read(){
    int x = 0,f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while('0' <= ch && ch <= '9'){
        x = x*10 + ch-'0';
        ch = getchar();
    }
    return x*f;
}

void add(int x,int y){
    to[++cnt] = y;
    nxt[cnt] = head[x];
    head[x] = cnt;
}

void clear(){
    memset(head,0,sizeof(head));
    memset(to,0,sizeof(to));
    memset(nxt,0,sizeof(nxt));
}

void tarjan(int u){
    dfn[u] = low[u] = ++now;
    sta[++top] = u;
    insta[u] = true;
    for(int i = head[u];i;i = nxt[i]){
        int v = to[i];
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(insta[v])
            low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u]){
        col[u] = ++num;
        insta[u] = false;
        while(sta[top] != u){
            int v = sta[top--];
            col[v] = num;
            insta[v] = false;
        }
        top--;
    } 
}

int main(){
    n = read();
    for(int i = 1;i <= n;i++)
        while(1){
            int j = read();
            if(!j) break;
            add(i,j);
            m++;
            x[m] = i, y[m] = j;
        }
    for(int i = 1;i <= n;i++)
        if(!dfn[i]) tarjan(i);
    clear();
    for(int i = 1;i <= m;i++)
        if(col[x[i]] != col[y[i]]){
            out[col[x[i]]]++;
            inn[col[y[i]]]++;
        }
    for(int i = 1;i <= num;i++){
        if(!inn[i]) ans1++;
        if(!out[i]) ans2++;
    }
    if(num == 1) printf("1
0
");
    else printf("%d
%d
",ans1,max(ans1,ans2));
    return 0;
}
原文地址:https://www.cnblogs.com/mogeko/p/13210935.html