POJ1236 SCC缩点+DAG性质

xg

题意

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

思路

  对于强连通分量,可以看作一个整体,然后进行缩点。

  至少提供多少个软件,其实就是求入度为0的点的个数。

  若使得一个DAG成为强连通图,实际就是零入度点的个数和零出度点的个数的最大值。所有都不需要建新图。

  特判一下已经是强连通图的情况。

  

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <vector> 
#define bug cout<<"--------------"<<endl
#define sp ' '
using namespace std;
typedef long long ll;

const int maxn = 1e5+10;
int tot = 0;
int head[maxn],ver[maxn],edge[maxn],nextt[maxn];
void add(int x,int y)
{
    ver[++tot] = y,nextt[tot] = head[x] , head[x] = tot;
}
int dfn[maxn],low[maxn],sta[maxn],c[maxn],ins[maxn];
vector<int>scc[maxn];

int in[maxn],out[maxn];
int n,num,top,cnt;
void tarjan(int x)
{
    dfn[x]=low[x]=++num;
    sta[++top]=x,ins[x]=1;
    for(int i=head[x];i;i=nextt[i])
    {
        int y=ver[i];
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(ins[y]){
            low[x]=min(low[x],dfn[y]);
        }
        
    }
    if(dfn[x]==low[x]){
        cnt++;int y;
        do{
            y=sta[top--],ins[y]=0;
            c[y]=cnt,scc[cnt].push_back(y);
        }while(x!=y);
    }
}

int main()
{
    //freopen("input.txt", "r", stdin);
    scanf("%d",&n);
    for(int i = 1;i <= n; ++i){
        int y ;
        while(scanf("%d",&y)){
            if(y == 0) break;
            add(i,y);
        }
    }

    for(int i =1 ;i <=n ;++i){
        if(!dfn[i]) tarjan(i);
    }
    for(int x =1 ;x <=n ;++x){
        for(int i =head[x] ;i;i = nextt[i]){
            int y = ver[i];
            if(c[x] == c[y]) continue;
           // addc(c[x],c[y]);
            in[c[y]]++;
            out[c[x]]++;
        }
    }
    //nub_edge = tc,nub_point = cnt;
    if(cnt == 1) {
        printf("1\n0"); 
        return 0;
    }
    int innub = 0,outnub = 0;
    for(int i = 1;i <= cnt;++i){
        if(!in[i]) innub++;
        if(!out[i]) outnub++;
    }
    printf("%d\n%d",innub,max(innub,outnub) );


}

 

  

posted @ 2020-08-22 17:23  阿斯水生产线  阅读(102)  评论(0编辑  收藏  举报