poj 1236 Network of Schools 強連通

我的第一個強連通題目,利用這個題目入門。花了一晚上學習了啥是強連通和tarjan算法求強連通分量。感覺這個題只要理解了這個就可以做了,比較適合入門。

如果還不會的,可以先了解一下再看題。

A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school.

Input
The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.
Output
Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.
Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
Sample Output
1
2

題意:給定一個有向圖,問你1:從幾個點開始可以遍歷所有的點。問你2:多加幾條邊可以使這個圖變成強連通圖
做法:
1.求幾個點開始,就是求有幾個入度爲0的強連通分量。
2,你讓每個強連通分量入度和出度都不爲0就行了,這樣就都連通了。做法就是把入度爲0的和出度爲0的連接起來,配不上的單獨連,這樣的話就取max(入度爲0的個數,出度爲0的個數)。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define ll long long
#define ld long double
#define INF 0x3f3f3f3f
using namespace std;
vector<int> G[105];
int vis[105],max_num=0,id[105];          //vis判斷是否訪問過,強連通分量個數,所屬強連通分量 
int stack[105],dfn[105],low[105];        //tarjan算法所用到的 
int top=0,now_dfn=0,rd[105],cd[105];     
void mem() {                              //初始化 
	memset(vis,0,sizeof vis);
	memset(id,0,sizeof id);
	memset(stack,0,sizeof stack);
	memset(dfn,0,sizeof dfn);
	memset(low,0,sizeof low);
	memset(rd,0,sizeof rd);
	memset(cd,0,sizeof cd);
}
void tarjan(int x) {                     //求強連通分量 
	vis[x]=1;
	stack[++top]=x;
	dfn[x]=low[x]=++now_dfn;
	for(int i=0; i<G[x].size(); i++) {
		int y=G[x][i];
		if(!vis[y]) {
			tarjan(y);
			low[x]=min(low[x],low[y]);
		} else
			low[x]=min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x]) {
		max_num++;
		int tmp;
		do {
			tmp=stack[top--];
			dfn[tmp]=INF;
			id[tmp]=max_num;
		} while(tmp!=x);
	}
}
int main() {
	//std::ios::sync_with_stdio(false);
	// freopen("in.txt", "r", stdin);
	// freopen("out.txt", "w", stdout);
	int n,x;
	cin>>n;
	mem();
	for(int i=1; i<=n; i++) {
		while(cin>>x&&x!=0) {
			G[i].push_back(x);
		}
	}
	for(int i=1; i<=n; i++) {             //可能圖不連通 
		if(!vis[i]) {
			tarjan(i);
		}
	}
	for(int i=1; i<=n; i++) {                   //求入度和出度 
		for(int j=0; j<G[i].size(); j++) {
			if(id[i]!=id[G[i][j]]) {
				rd[id[G[i][j]]]++;
				cd[id[i]]++;
			}
		}
	}
	int ansA=0,ansB=0;                       //入度爲0的個數,出度爲0的個數 
	for(int i=1; i<=max_num; i++) {
		if(rd[i]==0)
			ansA++;
		if(cd[i]==0)
			ansB++;
	}
	if(max_num==1)                         //只有一個強連通分量 
		cout<<1<<endl<<0<<endl;
	else
		cout<<ansA<<endl<<max(ansA,ansB)<<endl;
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章