CF915D Almost Acyclic Graph 拓撲排序

題面

題意:
給n個點,m條邊,有向圖,求是否能去掉一條邊使得原圖無環。
\(n<= 500, m <= min(n(n - 1), 10^5)\)

題解

一個樸素的想法:
枚舉刪哪條邊,然後用拓撲排序判斷是否還有環。
但是複雜度直接爆炸。
我們考慮刪邊對我們check過程(拓撲排序)的影響。
刪掉一條邊,相當於使得它的出點入度減一。
那麼不管我們刪掉哪條邊,只要它的出點一致,那麼在拓撲排序看來,我們的操作其實效果一樣。
也就是這樣會造成大量無用且重複的判斷。
所以我們考慮枚舉點。
如果一個點有入度,那麼我們嘗試刪除一條到這個點的邊,也就是讓這個點入度減一,然後用拓撲排序判斷一下是否有環。

#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 600
#define ac 101000

int n, m;
int in[AC], s[AC];
int q[AC], head, tail;
int Head[AC], date[ac], Next[ac], tot;

inline int read()
{
	int x = 0;char c = getchar();
	while(c > '9' || c < '0')  c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x;
}

inline void add(int f, int w){//加單項邊
	date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, in[w] ++, s[w] ++;
}

void pre()
{
	n = read(), m = read();
	for(R i = 1; i <= m; i ++)
	{
		int x = read(), y = read();
		add(x, y);
	}
}

bool t_sort()
{
	head = 1, tail = 0;
	for(R i = 1; i <= n; i ++) 
		if(!in[i]) q[++ tail] = i;
	while(head <= tail)
	{
		int x = q[head ++];
		for(R i = Head[x]; i; i = Next[i])
		{
			int now = date[i];
			if(!(-- in[now])) q[++ tail] = now;
		}
	}
	return tail == n;
}

void work()
{
	for(R i = 1; i <= n; i ++)
	{
		if(!in[i]) continue;
		-- in[i];
		if(t_sort())
		{
			printf("YES\n");
			return ;
		}
		memcpy(in, s, (n + 1) * 4);
    //    for(R j = 1; j <= n; j ++) in[j] = s[j];	
    }
	printf("NO\n");
}

int main()
{
//	freopen("in.in", "r", stdin);
	pre();
	work();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章