POJ 1236 Network of Schools(tarjan)题解

题意:一个有向图。第一问:最少给几个点信息能让所有点都收到信息。第二问:最少加几个边能实现在任意点放信息就能传遍所有点

思路:把所有强连通分量缩成一点,然后判断各个点的入度和出度

tarjan算法:问问神奇海螺啥是tarjan

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<queue>
#include<cmath>
#include<string>
#include<map>
#include<stack> 
#include<set>
#include<vector>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
const int N=110;
const int MOD=1000; 
using namespace std;
int n,index,scc_cnt;	//scc_cnt记录SCC 
int dfn[N],low[N],sccno[N],in[N],out[N];
vector<int> g[N];
stack<int> s;
void tarjan(int x){
	int i;
	dfn[x]=low[x]=++index;
	s.push(x);
	for(i=0;i<g[x].size();i++){
		int v=g[x][i];
		if(!dfn[v]){	//未走过 
			tarjan(v);
			low[x]=min(low[x],low[v]);
		}
		else if(!sccno[v]){	//走过且在栈中 
			low[x]=min(low[x],dfn[v]);
		}
	}
	if(dfn[x]==low[x]){
		scc_cnt++;	//增加一个大点  
		int a;
		while(1){	//x及以后全部出栈 
			a=s.top();
			s.pop();
			sccno[a]=scc_cnt;
			if(a==x) break;
		}
	}
}
void done(){
	index=scc_cnt=0;
	memset(dfn,0,sizeof(dfn));
	memset(sccno,0,sizeof(sccno));
	for(int i=0;i<n;i++){
		if(!dfn[i]) tarjan(i);
	}
}
int main(){
	int t;
	while(~scanf("%d",&n) && n){
		for(int i=0;i<n;i++) g[i].clear();
		for(int u=0;u<n;u++){
			while(~scanf("%d",&t) && t){
				t--;
				g[u].push_back(t);
			}
		}
		done();
		int ans1,ans2;
		for(int i=1;i<=scc_cnt;i++){
			in[i]=out[i]=0;	//入度出度初始化为无 
		}
		for(int i=0;i<n;i++){
			for(int j=0;j<g[i].size();j++){
				int v=g[i][j];
				if(sccno[i]!=sccno[v]){
					in[sccno[v]]=out[sccno[i]]=1;	//一个有入度一个有出度 
				}
			}
		}
		ans1=ans2=0;
		for(int i=1;i<=scc_cnt;i++){
			if(in[i]==0) ans1++;
			if(out[i]==0) ans2++;
		}
		if(scc_cnt==1) printf("1\n0\n");
		else printf("%d\n%d\n",ans1,max(ans1,ans2));
	}
	return 0;
}

posted @ 2018-03-29 22:20  KirinSB  阅读(163)  评论(0编辑  收藏  举报