1. 程式人生 > 其它 >#拓撲排序#洛谷 5157 [USACO18DEC]The Cow Gathering P

#拓撲排序#洛谷 5157 [USACO18DEC]The Cow Gathering P

拓撲排序

題目

給出一棵樹和一些限制關係 \((a_i,b_i)\)

一種合法的刪點序列當且僅當刪除一個點之後樹的大小不超過 1 或不存在孤立點,

並且 \(a_i\) 要比 \(b_i\) 先刪除,問 \(\forall x\in [1,n]\),是否可能為合法刪點序列的末項


分析

考慮到限制就是 \(a_i\) 不包含 \(b_i\) 的那些子樹包括 \(a_i\) 本身不可能為末項。

並且如果有一個點可能為末項,那麼與其不通過被限制的點相連的也可以成為末項。

所以只要找到一個合法的末項即可,如果沒有限制隨便挑一個就行了。

考慮把限制看成單向邊,每次把所謂的葉子加進佇列,

如果葉子發現度數為 0 說明無論限制還是樹均被滿足,那麼它就可以成為末項


程式碼

#include <cstdio>
#include <cctype>
#include <vector>
using namespace std;
const int N=100011;
struct node{int y,next;}e[N<<1]; vector<int>G[N];
int as[N],ans[N],q[N],head=1,tail,deg[N],n,et=1,m,rt;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int Topsort(){
	for (int i=1;i<=n;++i)
	    if (deg[i]==1) q[++tail]=i;
	while (head<=tail){
		int x=q[head++];
		if (deg[x]<1) return x;
		for (int i=as[x];i;i=e[i].next)
		    if (--deg[e[i].y]==1) q[++tail]=e[i].y;
		for (int i=0;i<(int)G[x].size();++i)
		    if (--deg[G[x][i]]==1) q[++tail]=G[x][i];
	}
	return tail==n;
}
void dfs(int x){
	ans[x]=1;
	for (int i=as[x];i;i=e[i].next)
	    if (!ans[e[i].y]) dfs(e[i].y);
}
int main(){
	n=iut(),m=iut();
	for (int i=1;i<n;++i){
		int x=iut(),y=iut();
		e[++et]=(node){y,as[x]},as[x]=et,++deg[x];
		e[++et]=(node){x,as[y]},as[y]=et,++deg[y];
	}
	for (int i=1;i<=m;++i){
		int x=iut(),y=iut();
		G[x].push_back(y);
		ans[x]=-1,++deg[y];
	}
	rt=Topsort();
	if (!rt){
		for (int i=1;i<=n;++i)
		    putchar(48),putchar(10);
		return 0;
	}
	dfs(rt);
	for (int i=1;i<=n;++i,putchar(10))
	if (ans[i]==1) putchar(49);
        else putchar(48);
	return 0;
}