首页 > 其他分享 >洛谷 P4429 [BJOI2018] 染色

洛谷 P4429 [BJOI2018] 染色

时间:2024-01-31 17:13:41浏览次数:41  
标签:度数 BJOI2018 洛谷 int ge P4429 maxn return deg

洛谷传送门

LOJ 传送门

非常有趣的结论题。

首先显然,整个图不是二分图就无解。

然后显然每个连通块独立,可以分连通块判定。

然后发现一度点是没什么用的,因为无论和它相连的点颜色是什么,它都能找到一种和这种颜色不同的颜色。所以考虑类似拓扑排序剥一度点。剩下的图的 \(deg_u \ge 2\)。

考虑若有一个偶环 \(1 \to 2 \to 3 \to 4 \to 1\),可以 \(\{A, B\}, \{A, B\}, \{B, C\}, \{A, C\}\),容易发现这样可以钦定 \(1\) 号点染 \(B\)。

所以若有两个仅交于一点或者不交的偶环就寄了,因为通过钦定一定可以导出矛盾。

进一步地,若有两个不重合部分点数 \(\ge 2\) 的偶环就寄了,因为可以让不公共部分放 \(\{B, C\}, \{A, C\}\),公共部分放 \(\{A, B\}\),也可以导出矛盾。

考虑如何快速判断这个东西。

不妨研究一下这个图的度数特点。考虑若存在两个度数 \(\ge 3\) 的点 \(u, v\),取出任意三条 \(u \to v\) 的路径 \(P_1, P_2, P_3\)。

考虑若两条路径 \(P_1, P_2\) 存在除 \(u, v\) 外的交点 \(w_1, w_2, \ldots, w_k\),那么让 \(u \to w_1 \to u, v \to w_k \to v\) 即可构造出无解(此时认为路径在第一个点和最后一个点不重合)。

所以 \(P_1, P_2, P_3\) 一定两两不交。不妨设 \(|P_1| \le |P_2| \le |P_3|\)(定义路径长度为经过的边数)。有解当且仅当 \(|P_1| = |P_2| = 2\)。

考虑存在度数 \(\ge 4\) 的点也寄了,因为要么其他点度数都 \(\ge 2\)(此时为两个重合于一点的环),要么存在一个点度数 \(\ge 3\)。

所以有解的充要条件为:

  • 不存在度数 \(\ge 4\) 的点;
  • 不存在度数 \(\ge 3\) 的点,或存在且仅存在两个度数 \(\ge 3\) 的点 \(x, y\),使得存在至少两个度数 \(= 2\) 的点连接 \(x, y\)。
code
// Problem: P4429 [BJOI2018] 染色
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4429
// Memory Limit: 500 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<int, int> pii;

const int maxn = 10050;

int n, m, a[maxn], fa[maxn], deg[maxn];
vector<int> G[maxn], vc[maxn];
bool e[maxn][maxn];

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

inline void merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		fa[x] = y;
	}
}

bool dfs(int u) {
	for (int v : G[u]) {
		if (a[v] == -1) {
			a[v] = a[u] ^ 1;
			if (!dfs(v)) {
				return 0;
			}
		} else if (a[v] == a[u]) {
			return 0;
		}
	}
	return 1;
}

void solve() {
	mems(e, 0);
	mems(a, -1);
	mems(deg, 0);
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		fa[i] = i;
		vector<int>().swap(G[i]);
		vector<int>().swap(vc[i]);
	}
	while (m--) {
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].pb(v);
		G[v].pb(u);
		merge(u, v);
		++deg[u];
		++deg[v];
		e[u][v] = e[v][u] = 1;
	}
	for (int i = 1; i <= n; ++i) {
		vc[find(i)].pb(i);
	}
	for (int i = 1; i <= n; ++i) {
		if (a[i] == -1 && !dfs(i)) {
			puts("NO");
			return;
		}
	}
	for (int _ = 1; _ <= n; ++_) {
		if (vc[_].empty()) {
			continue;
		}
		queue<int> q;
		for (int i : vc[_]) {
			if (deg[i] == 1) {
				q.push(i);
			}
		}
		while (q.size()) {
			int u = q.front();
			q.pop();
			for (int v : G[u]) {
				if ((--deg[v]) == 1) {
					q.push(v);
				}
			}
		}
		int x = -1, y = -1;
		for (int i : vc[_]) {
			if (deg[i] >= 4) {
				puts("NO");
				return;
			}
			if (deg[i] == 3) {
				if (x == -1) {
					x = i;
				} else if (y == -1) {
					y = i;
				} else {
					puts("NO");
					return;
				}
			}
		}
		if (x != -1) {
			int cnt = 0;
			for (int i : G[x]) {
				if (deg[i] == 2 && e[x][i] == e[y][i]) {
					++cnt;
				}
			}
			if (cnt < 2) {
				puts("NO");
				return;
			}
		}
	}
	puts("YES");
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:度数,BJOI2018,洛谷,int,ge,P4429,maxn,return,deg
From: https://www.cnblogs.com/zltzlt-blog/p/17999671

相关文章

  • 洛谷题单指南-暴力枚举-P1088 [NOIP2004 普及组] 火星人
    原题链接:https://www.luogu.com.cn/problem/P1088题意解读:火星人的手指可以通过全排列来表示数字,全排列由小到大的顺序即为表示的数字大小,题目可以转化为:给定按顺序全排列中的某一个排列,求往后数m个排列的内容。解题思路:此题与经典全排列问题的差异在于,需要从指定一个排列开......
  • 洛谷题单指南-暴力枚举-P1706 全排列问题
    原题链接:https://www.luogu.com.cn/problem/P1706题意解读:n个数全排列问题,本质上,给定n个空位,枚举每个能填入空位的数,依次填入,每个数只能填一次。解题思路:如何填入n个数呢,可以借助于递归,流程如下:dfs(填入第k个数){如果已经填满n个数输出结果返回......
  • 洛谷题单指南-暴力枚举-P1157 组合的输出
    原题链接:https://www.luogu.com.cn/problem/P1157题意解读:在1~n的数中挑选r个,有多少种组合,与P1036类似,有两种做法:二进制法、DFS,下面给出DFS版的代码。100分代码:#include<bits/stdc++.h>usingnamespacestd;constintN=25;intn,r;intt[N];voiddfs(intk){......
  • 洛谷题单指南-暴力枚举-P1036 [NOIP2002 普及组] 选数
    原题链接:https://www.luogu.com.cn/problem/P1036题意解读:题目即要在n个数中,枚举出所有的子集,当子集中数字个数刚好为k时,求和,判断是否是素数。解题思路:方法一:二进制法通过二进制法,可以枚举一个集合中所有元素“选”或者“不选”的情况,用二进制1表示选该元素,二进制0表示不选。......
  • 洛谷题单指南-暴力枚举-P1618 三连击(升级版)
    原题链接:https://www.luogu.com.cn/problem/P1618题意解读:枚举所有三位数的组合情况,判断是否符合比例。解题思路:方法一:枚举第一个数根据题意,目的是寻找三个符合比例的三位数,可以直接枚举第一个,最小是123,最大是987设第一个数为x,三个数的比例关系是a:b:c设另外两个数为y,z那么,根......
  • 洛谷题单指南-暴力枚举-P2241 统计方形(数据加强版)
    原题链接:https://www.luogu.com.cn/problem/P2241题意解读:要在整个n*m区域计算正方形和长方形的个数,枚举法即可。解题思路:此题枚举的对象是矩形的高i和宽j,高的范围[1,n],宽的范围[1,m],然后计算在n*m区域内有多少个i*j,i==j即属于正方形,i!=j属于长方形。那么,问题就集中在了......
  • 洛谷题单指南-排序-P1012 [NOIP1998 提高组] 拼数
    原题链接:https://www.luogu.com.cn/problem/P1012题意解读:通过某种合理的排序方式,使得排序后的数字连在一起最大。解题思路:此题关键在于排序,对于两个数字,哪个数字应该排在前面呢?1、思考误区很容易想到,给定两个数abcd、xyz,先比较第一位a和x,谁大谁排前面,一直到c和z。再来看d,这......
  • 洛谷题单指南-排序-P1104 生日
    原题链接:https://www.luogu.com.cn/problem/P1104题意解读:将学生按照年龄由大到小排序,如果年龄相同,后输入的排在前面,输出排序后的学生姓名。解题思路:此题是一个排序常规题,年龄大排在前说明年、月、日越小越在前面,核心的排序思路如下:1、如果年份不同,按年份由小到大排序2、如果......
  • 洛谷题单指南-排序-P5143 攀爬者
    原题链接:https://www.luogu.com.cn/problem/P5143题意解读:给出一系列的点,按某种顺序经过所有点,计算距离。解题思路:如果小学生,可能对于三维坐标距离有些陌生,没关系,题目已经给出了计算公式,直接套公式即可,关键步骤如下:1、读取所有坐标点2、按高度值从小到大排序3、从头依次计算......
  • 洛谷题单指南-排序-P1068 [NOIP2009 普及组] 分数线划定
    原题链接:https://www.luogu.com.cn/problem/P1068题意解读:根据题意,用模拟法,求出分数线所在位置,然后计算分数线,最后输出结果即可。解题思路:1、分数线是按从大到小排名来设定,因此数据因为按照分数从大到小排序,如果分数相同,需要安装报名号从小到大排序2、计算分数线位置,主要是下......