luogu P2746 [USACO5.3]校园网Network of Schools 题解

前言:

火星题。。。
但是我调了半天,最后看了题解才明白。
Wtcl

解析:

显然先缩个点。
第一问,就是问多少入度为0的点。
第二问,抽象一下就是要添加一些边,让一个DAG变成一个SCC,求最小边数。
答案就是max(入度0的数量,出度0的数量)
震惊,我竟然没看出来,活到爆!
代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1000000+10;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < ‘0‘ || c > ‘9‘) { if (c == ‘-‘) f = -1; c = gc();} while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + (c & 15), c = gc(); f * x; })
char buf[1 << 20], *p1, *p2;
int n,cnt,tot,top,ss,Time,sss;
struct node{
	int to,nxt;
}edge[maxn<<1];
int head[maxn],belong[maxn],dfn[maxn],low[maxn],Stack[maxn],ind[maxn],outd[maxn];
bool vis[maxn];
void add(int from,int to){
	edge[++cnt].to=to;
	edge[cnt].nxt=head[from];
	head[from]=cnt;
}
void tarjan(int u){
	if(dfn[u]) return;
	dfn[u]=low[u]=++Time;
	vis[u]=1;
	Stack[++top]=u;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}else if(vis[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		tot++;
		while(Stack[top+1]!=u){
			int t=Stack[top];
			top--;
			vis[t]=0;
			belong[t]=tot;
		}
	}
}
void Solve(){
	scanf("%d",&n);
	for(int i=1,x;i<=n;++i){
		while(1){
			scanf("%d",&x);
			if(x==0) break;
			add(i,x);
		}
	}
	for(int i=1;i<=n;++i) tarjan(i);
	for(int u=1;u<=n;++u){
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(belong[u]==belong[v]) continue;
			ind[belong[v]]++;
			outd[belong[u]]++;
		}
	}
	for(int i=1;i<=tot;++i) if(ind[i]==0) ss++;
	for(int i=1;i<=tot;++i) if(outd[i]==0) sss++;
	int ans;
	if(tot==1) ans=0;
	else ans=max(ss,sss);
	printf("%d\n%d\n",ss,ans);
}
int main(){
	Solve();
	return 0;
}


luogu P2746 [USACO5.3]校园网Network of Schools 题解

上一篇:JS实现提示跳转功能


下一篇:CSS-Photoshop投影与CSS中box-shadow的转换