3.1 有向图的环

☆问题描述:
给定一张N个点M条边的有向图,判断该有向图是否存在环?

☆数据输入:
输入有若干组,第一行有两个整数N,M(N≤100000,M≤200000),表示N个点M条有向边。
接下来M行,每行两个整数U,V表示一条U到V的有向边。顶点编号1-N。

☆结果输出:
输出YES表示存在环,NO表示不存在环。

☆输入示例:
3 3
1 2
2 3
3 1
☆输出示例:
YES

解题思路:
拓扑排序裸题,没什么好说的。vector以及queue的使用能够让解决问题的过程更加顺畅
拓扑排序:对一个有向图里的所有点进行排序,该排序满足这样的条件:对有向图中任意两点u、v,若存在一条有向边从u指向v,那么在排序过程中u就要出现在v前面。当且仅当一个有向图为有向无环图(directed acyclic graph,或称DAG)时,才能得到对应于该图的拓扑排序,每一个有向无环图都至少存在一种拓扑排序。
过程: 先统计所有点的入度,首先找到的入度为0的点就排在第一位,然后把这个点在图里“删除”,并且这个点指向的所有点的入度都减一;重复以上操作直到图里所有点都被“删除”时,拓扑排序完成,若删除到最后仍有点留下,则该图存在环,无拓扑排序。
时间复杂度O(n+e),n为点的总数,e为边的总数。
在这里插入图片描述

//Matsuri
#include<bits/stdc++.h>
#define MAX 200009
using namespace std;

int n,m;
int in[MAX]; // 点的入度 
queue<int>q;
vector<int>edge[MAX]; // 存图用,二维vector 
// edge[i].size():与编号为i的点相连的其他点的数量; edge[i][]:访问和点i相连的其他点 
vector<int>ans; // 拓扑排序序列  

int main()
{
	scanf("%d%d",&n,&m);
	int u,v;
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		edge[u].push_back(v);  // 建立图的过程,举例:u点连向v点,则edge[u][0]=v,若u点还有和别的点连则二维参数++ 
		in[v]++;
	}
	for (int i=1;i<=n;i++)	if (in[i]==0) q.push(i); // 遍历找到入度为0的点,然后入队列
	while(!q.empty())
	{
		// 拓扑排序过程 
		int p=q.front(); //选择一个入度为0的点,然后出队列 
		q.pop();
		ans.push_back(p);
		for (int i=0;i<edge[p].size();i++)
		{
			int next=edge[p][i];
			in[next]--;
			if (in[next]==0) q.push(next);
		}	
	} 
	
	if (ans.size()==n) puts("NO");
	else puts("YES");
		
	return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值