洛谷P2746校园网

传送门啦

下面来看任务B。我们发现,图中只要存在入度为0的点和出度为0的点就永远不可能满足要求:“ 不论我们给哪个学校发送新软件,它都会到达其余所有的学校 ”。我们还发现,只要在入度为0的点和出度为0 的点之间连一条边,就可以同时消灭两个“不合法”的点。如果不能做到刚好两两配对(不妨假设入度为0的点多),就给每个多出来的入度为0的点随便找一个出度为0的点配对(也就是说一个点可以同时配多个点)。因此,入度为0的点数与出度为0的点数的较大值即为任务B的答案。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10005;
const int maxm = 5e6 + 6;
int read(){
	char ch = getchar();
	int f = 1 , x = 0;
	while(ch > '9' || ch < '0'){
		if(ch == '-')  f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

int n,m,s;
int head[maxn],tot;
int dfn[maxn],low[maxn],ind;
int stack[maxn],top,num[maxn],belong[maxn],cnt;
bool ins[maxn];
int in[maxn],chu[maxn],ans1,ans2;
struct Edge{
	int from,to,next;
}edge[maxm];

void add(int u , int v){
	edge[++tot].from = u;
	edge[tot].to = v;
	edge[tot].next = head[u];
	head[u] = tot;
} 

void tarjan(int x){
	low[x] = dfn[x] = ++ind;
	ins[x] = true;
	stack[++top] = x;
	for(int i=head[x];i;i=edge[i].next){
		int v = edge[i].to;
		if(ins[v])  low[x] = min(low[x] , dfn[v]);
		if(!dfn[v]) {
			tarjan(v);
			low[x] = min(low[x] , low[v]);
		} 
	}
	int k = 0;
	if(dfn[x] == low[x]){
		cnt++;
		do{
			k = stack[top];
			num[cnt]++;
			top--;
			ins[k] = false;
			belong[k] = cnt;
		}  while(k != x);
	}
}

int main(){
	n = read();
	for(int i=1;i<=n;i++){
		while((s = read()) != 0){
			m++;
			add(i , s);
		}
	}
	//printf("%d
",m);
	for(int i=1;i<=n;i++)
	  if(!dfn[i])  tarjan(i);
	for(int i=1;i<=m;i++)
	  if(belong[edge[i].from] != belong[edge[i].to]){
	  	  in[belong[edge[i].to]]++;
	  	  chu[belong[edge[i].from]]++;
	  }
	if(cnt == 1){
		printf("1
0
");
		return 0;
	}  
	else{
		for(int i=1;i<=cnt;i++){
			if(in[i] == 0)  ans1++;
			if(chu[i] == 0)  ans2++;
		}
		printf("%d
%d",ans1,max(ans1 , ans2));
		return 0;
	}
	
}

/*
10
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
1 0
*/ 
顺风不浪,逆风不怂。
原文地址:https://www.cnblogs.com/Stephen-F/p/9883268.html