DFS树

参考:CF1325F Ehab’s Last Theorem(dfs树


简单定义为一颗由 d f s dfs dfs 生成而来的树
一颗 d f s dfs dfs树的边分为树边和非树边
在这里插入图片描述
深色的是树边,浅色的是非树边

d f s dfs dfs树的性质:
①:每条非树边 ( u , v ) (u, v) (u,v) 都连向子树中某个点,且一定具有祖先关系
②:子树之间不存在非树边

因此 u u u v v v 在树上的链 与 非树边 ( u , v ) (u, v) (u,v) 可以形成一个环,环的大小为 ∣ d e p [ u ] − d e p [ v ] ∣ + 1 |dep[u] - dep[v]| + 1 dep[u]dep[v]+1
由此可以找出无向图的环,也可以找最大环和最小环


例题: Codeforces Round #649 (Div. 2) D. Ehab’s Last Corollary

题目大意:
     n n n 个点 m m m 条边的无向图,给定一个 k k k,找出满足下面任何一个条件的答案:
    一个独立集,点数恰为 ⌈ k 2 ⌉ \lceil\frac{k}{2}\rceil 2k
    一个环,点数不超过 k k k

解题思路:
    其实很好想,分三种情况:
    ①:能在图中找到一个点数不超过 k k k 个的环,则输出这个环
    ②:能找到环,但最小环的点数大于 k k k,则最小环上可以找到点数恰为 ⌈ k 2 ⌉ \lceil\frac{k}{2}\rceil 2k 的独立集
    ③:无环,则原图为二分图,直接染色找独立集即可

    发现 ② 和 ③ 可以用分层染色处理,关键是怎么找最小环
    因此直接用 d f s dfs dfs树处理即可

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 2e5 + 5;
int n, m, k, flag;
int dep[maxn], fa[maxn];
vector <int> g[maxn], col[2], cyc;

void find(int u, int v){
	while(u ^ v){
		cyc.push_back(u);
		u = fa[u];
	}
	cyc.push_back(v);
}

void dfs(int u, int f){
	fa[u] = f; dep[u] = dep[f] + 1;
	col[dep[u] & 1].push_back(u);
	for(auto v : g[u]){
		if(v == f) continue;
		if(!dep[v]) dfs(v, u);
		else if(dep[u] > dep[v]){
			if(dep[u] - dep[v] + 1 <= k){
				if(flag) continue;
				flag = 1; find(u, v);
			}
		}
	}
}

signed main() {
    scanf("%d%d%d", &n, &m, &k);
    for(int i=1, u, v; i<=m; i++) {
		scanf("%d%d", &u, &v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
    dfs(1, 0);
    if(flag) {
		printf("2\n%d\n", cyc.size());
		for(auto i : cyc) printf("%d ", i);
	} else {
		int num = (k + 1) / 2;
		int op = col[0].size() > col[1].size() ? 0 : 1;
		printf("1\n");
		for(auto i : col[op]) {
			printf("%d ", i); num--;
			if(num == 0) break;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值