【拓扑排序专题】CodeForces - 915D Almost Acyclic Graph

https://vjudge.net/problem/CodeForces-915D

D. Almost Acyclic Graph

Description

You are given a directed graph consisting of n vertices and m edges (each edge is directed, so it can be traversed in only one direction). You are allowed to remove at most one edge from it.

Can you make this graph acyclic by removing at most one edge from it? A directed graph is called acyclic iff it doesn't contain any cycle (a non-empty path that starts and ends in the same vertex).

Input

The first line contains two integers n and m (2 ≤ n ≤ 500, 1 ≤ m ≤ min(n(n - 1), 100000)) — the number of vertices and the number of edges, respectively.

Then m lines follow. Each line contains two integers u and v denoting a directed edge going from vertex u to vertex v (1 ≤ u, v ≤ nu ≠ v). Each ordered pair (u, v) is listed at most once (there is at most one directed edge from u to v).

Output

If it is possible to make this graph acyclic by removing at most one edge, print YES. Otherwise, print NO.

Examples

input

3 4
1 2
2 3
3 2
3 1

output

YES

input

5 6
1 2
2 3
3 2
3 1
2 1
4 5

output

NO

Note

In the first example you can remove edge , and the graph becomes acyclic.

In the second example you have to remove at least two edges (for example,  and ) in order to make the graph acyclic.

思路

题目大意:给定一个有向图,若至多删去一条边,仍未无环图,则输出“YES”;反之,若有环,则输出“NO”

题目思路:若至多删去一条边,分两种情况:(1)删去0条边,此时判断一下;(2)删去一条边,再判断。

如何删去一条边是本题关键。我们可以枚举删去的边,也就是枚举每个顶点,让其入度-1(删去指向到该点的一条边),

此时再toposort()进行判断。

注意:本题toposort()中需要删去一行代码:G【u】.clear().,不然结果错误。

AC Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector> 
#include <queue>
#include <algorithm>
using namespace std;
const int nmax=505;
int inDegree[nmax];//存每个节点的入度
int ruDegree[nmax];//存每个节点的入度
vector<int>G[nmax];//邻接表 
int n,m;//点数,边数 
bool toposort(){
	int num=0;//加到拓扑序列的顶点数
	queue<int>q;
	while(!q.empty()) q.pop();//清空队列
	for(int i=1;i<=n;i++){//顶点编号:1~N
		if(inDegree[i]==0){
			q.push(i);//把入度为0的顶点扔进队列 
		} 
	} 
	while(!q.empty()){
		int u=q.front();
		q.pop();//删除该点
		num++; 
		for(int i=0;i<G[u].size();i++){//遍历与点u相邻的所有边,删除之。 
			int v=G[u][i];
			inDegree[v]--;
			if(inDegree[v]==0){
				q.push(v);
			} 
		} 
		//G[u].clear(); //加这一行就错了 
	}
	//printf("%d\n",num);
	if(num==n) return true;
	else return false;//有环路 
}

int main(int argc, char** argv) {
	while(~scanf("%d %d",&n,&m)){
		for(int i=1;i<=n;i++){//初始化清空邻接表 
			G[i].clear();
		}
		memset(inDegree,0,sizeof(inDegree));
		memset(ruDegree,0,sizeof(ruDegree));
		int u,v;
		for(int i=0;i<m;i++){
			scanf("%d %d",&u,&v);
			G[u].push_back(v);
			inDegree[v]++; 
			ruDegree[v]++; 
		} 
		int flag;
		if(toposort()){//不用删边,就是DAG了 
			puts("YES");
			continue;	
		}
		else{//有环,删除一条边再判断 
			flag=0;
			for(int i=1;i<=n;i++){
				memcpy(inDegree,ruDegree,sizeof(ruDegree));
				if(inDegree[i]>=1){
					inDegree[i]--;//删除一条边<=>该顶点的入度--; 
					if(toposort()){
						flag=1;
						puts("YES\n");
						break; 
					}
				}
			}
		}
		if(flag==0){
			puts("NO\n");
		}
		
	} 
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值