
Codeforces Round #346 (Div. 2) F. Polycarp and Hay(并查集+bfs)
每个连通块的大小不超过k/x。 每个连通块内的边权值总和至少为z。
发布日期:2021-05-08 15:17:29
浏览次数:13
分类:精选文章
本文共 3143 字,大约阅读时间需要 10 分钟。
问题是在判断是否可以将图中的边划分成k/x个连通块,每个连通块满足以下条件:
以下是对问题的详细分析和解答:
问题分析
给定一个二维网格图,每个节点有边权值。问题要求判断是否存在一种连通块划分方式,将图中的边划分为k/x个连通块,每个连通块满足以下条件:
- 连通块的大小不超过k/x。
- 连通块内的边权值总和至少为z。
这个问题可以通过并查集和广度优先搜索(BFS)来解决,具体步骤如下:
解决思路
排序节点:按照边权值从大到小排序节点,确保处理最大的边权值优先。
并查集初始化:每个节点初始时是自己的父节点,数值初始化为1,表示每个节点初始时是一个连通块。
处理每个节点:从大到小处理每个节点,检查其邻居。如果邻居满足条件,合并当前节点所在的连通块。
检查条件:在处理每个节点时,检查是否满足k能被z整除,并计算t=k/z。如果当前连通块的数值满足条件,说明可以将图划分为t个连通块,每个连通块满足要求,返回“YES”。
构造连通块:如果满足条件,调用BFS构造t个连通块,输出结果。
解决代码
#includeusing namespace std;typedef long long ll;const int maxn = 1e6 + 5;const int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};int father[maxn], a[1001][1001];vector v;struct Node { int x, y, z;};bool cmp(const Node &a, const Node &b) { return a.z > b.z;}int findfather(int x) { if (x == father[x]) return x; int i = findfather(father[x]); father[x] = i; return i;}void unit(int a, int b) { int fa = findfather(a), fb = findfather(b); if (fa != fb) { father[fa] = fb; num[fb] += num[fa]; num[fa] = 0; }}void bfs(int x, int y, ll cnt, ll z) { queue q; q.push({x, y, a[x][y]}); vis[x][y] = 1; cnt--; while (!q.empty()) { Node t = q.front(); q.pop(); int x = t.x, y = t.y, w = t.z; for (int j = 0; j < 4; ++j) { if (cnt == 0) break; int nx = x + dir[j][0], ny = y + dir[j][1]; if (nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny]) continue; if (a[nx][ny] >= z) { vis[nx][ny] = 1; q.push({nx, ny, a[nx][ny]}); cnt--; } } } for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) { if (vis[i][j]) printf("%d", z); else printf("0"); if (j == m) printf("\n"); }}int main() { ll k; for (int i = 0; i < maxn; ++i) { father[i] = i; num[i] = 1; } n, m, k; for (int i = 0; i < v.size(); ++i) { int x, y; scanf("%d", &a[i][0]); v.push_back({i + 1, i + 1, a[i][0]}); } sort(v.begin(), v.end(), cmp); for (int i = 0; i < v.size(); ++i) { int x = v[i].x, y = v[i].y, z = v[i].z; for (int j = 0; j < 4; ++j) { int nx = x + dir[j][0], ny = y + dir[j][1]; if (nx < 1 || nx > n || ny < 1 || ny > m) continue; if (a[nx][ny] >= z) { unit((nx - 1) * m + ny, (x - 1) * m + y); } } if (k % z != 0) continue; ll t = k / z; if (t <= num[findfather((x - 1) * m + y)]) { puts("YES"); bfs(x, y, t, z); return 0; } } puts("NO");}
代码解释
并查集初始化:每个节点初始时是自己的父节点,数值为1。
排序节点:按边权值从大到小排序,确保处理最大的边权值优先。
处理节点:从大到小处理每个节点,检查邻居并进行并查集操作,合并连通块。
条件检查:检查是否满足k能被z整除,并计算t=k/z。若当前连通块的数值满足条件,返回“YES”并构造连通块。
构造连通块:调用BFS构造t个连通块,输出结果。
结论
通过以上方法,可以高效地判断图是否可以划分为k/x个连通块,每个连通块满足大小和边权值的条件。如果满足条件,返回“YES”;否则,返回“NO”。
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2025年04月17日 04时01分29秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
SpringBoot笔记
2019-03-06
让你的代码更优秀的 14 条建议
2019-03-06
不需要爬虫也能轻松获取 unsplash 上的图片
2019-03-06
将博客搬至CSDN
2019-03-06
elementUi源码解析(1)--项目结构篇
2019-03-06
自动遍历测试之Monkey工具
2019-03-06
Nmap扫描工具介绍
2019-03-06
算法笔记:递归、动态规划
2019-03-06
Pytest插件开发
2019-03-06
常用Windows 快捷键
2019-03-06
linux命令-压缩与打包
2019-03-06
ORACLE 11g 生产中高水位线(HWM)处理
2019-03-06
centos 6.x 编译安装 pgsql 9.6
2019-03-06
weblogic 服务器部署SSL证书
2019-03-06
oracle 11g not in 与not exists 那个高效?
2019-03-06