【51nod 2846】无向图找无弦环(tarjan)

121 篇文章 2 订阅
27 篇文章 0 订阅

无向图找无弦环

题目链接:51nod 2846

题目大意

给你一个无向图,要你找一个无弦环。
无弦环是指一个环里面的点除了环连着的点对别的之间都没有边。

思路

首先由一个很暴力的想法就是我们找最小环,而这个肯定是可以的。
因为我们会发现如果一个环有弦是因为里面插了一条(或者若干条)边,那我们完全可以把它分成两个(或者多个)小的环,那我们找到最小的环,它里面肯定不就没有边了。
但是你会发现常规的找最小环的方法是 Floyed 算法,复杂度达到了 O ( n 3 ) O(n^3) O(n3) 过不了,而且你要输出方案是会比较麻烦的。

那我们考虑别的方法,考虑有什么别的东西也可以找环。
不难想到 Tarjan 这个东西,而且你想一想会发现你可以把它简化一下得到。
那每次到一个点我们先看它的每个儿子中有没有可以到之前到过的点,那如果有就代表出现环了,那我们要保证没有弦,那我们就可以找 d f s dfs dfs 序距离当前最近的一个点,然后把栈中的那个部分拿出来输出即可。
如果没有,那我们就走,走就随便走,毕竟你找到一个答案就可以直接结束整个程序了。
然后要记得你搜完一个个要把它从栈中弹出来。

然后搞就可以啦。

代码

#include<cstdio>
#include<cstdlib> 

using namespace std;

const int N = 2e5 + 100;
struct node {
	int to, nxt, op;
}e[N << 1];
int n, m, le[N], KK;
int dfn[N], sta[N];
int ans[N];

void add(int x, int y) {
	e[++KK] = (node){y, le[x], KK + 1}; le[x] = KK;
	e[++KK] = (node){x, le[y], KK - 1}; le[y] = KK;
}

void tarjan(int now, int bef) {
	dfn[now] = ++dfn[0]; sta[++sta[0]] = now;
	bool end = 0; int pla = -1;
	for (int i = le[now]; i; i = e[i].nxt) {
		if (e[i].op == bef) continue;
		if (!dfn[e[i].to]) continue;
			else {
				if (!end) pla = e[i].to, end = 1;
					else pla = dfn[pla] < dfn[e[i].to] ? e[i].to : pla;
			}
	}
	if (end) {
		while (sta[sta[0]] != pla) ans[++ans[0]] = sta[sta[0]--];
		ans[++ans[0]] = sta[sta[0]];
		printf("%d\n", ans[0]); for (int i = 1; i <= ans[0]; i++) printf("%d ", ans[i]);
		exit(0);
	}
	for (int i = le[now]; i; i = e[i].nxt)
		if (e[i].op == bef) continue;
			else tarjan(e[i].to, i);
	sta[sta[0]--] = 0;
}

int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; i++) {
		int x, y; scanf("%d %d", &x, &y);
		add(x, y);
	}
	
	for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, 0);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值