清华学堂在线OJ——无线广播(Broadcast)

https://dsa.cs.tsinghua.edu.cn/oj/problem.shtml?id=1148
用BFS太浪费了,所以选择了更精简的并查集
由于要用两种颜色染色,所以分别用(2n-1)和(2n)表示同一类的两种颜色,初始状态点的颜色均为(2n-1),每读入一条边进行类的同步(集合的合并)或冲突判断。

//并查集
#pragma warning(disable : 4996)//防止vs对scanf报错
#include<iostream>
#include<cstdio>
using namespace std;

int color[20001];//以索引号表示颜色,以对应值表示该颜色所在集合的代表颜色。初始值为0。
				 //对于点n,其颜色为(2n-1),与其相异的颜色为(2n)。
				 //如:color[2n-1]表示(2n-1)所在集合的代表颜色
				 //代表颜色的代表颜色的……直到color[X]=0,此时的X称为最高代表颜色
				 //颜色属于{(2n-1),(2n)}称为同类;颜色相同称为同色

int Findcolor(int pcolor) {//查询某一颜色所在集合的最高代表颜色
	if (color[pcolor] == 0)//找到了最高代表颜色
		return pcolor;
	return color[pcolor] = Findcolor(color[pcolor]);//递归查找代表颜色的代表颜色,并压缩查询路径长度
}

int main() {
	int pointnum, edgenum;//点数,边数
	scanf("%d%d", &pointnum, &edgenum);
	int a, b;//边两端点
	int acolor, bcolor;//两端点所在集合最高代表颜色
	while (0 < edgenum--) {
		scanf("%d%d", &a, &b);
		acolor = Findcolor(a * 2 - 1);//对于点n,其颜色为(2n-1)
		bcolor = Findcolor(b * 2 - 1);//对于点n,其颜色为(2n-1)
		if ((acolor + 1) / 2 == (bcolor + 1) / 2) {//同类
			if (acolor == bcolor) {//同色,颜色冲突,染色失败,输出-1,,程序结束
				printf("-1");
				return 0;
			}
			//同类不同色,无冲突,无需处理
		}
		else {//不同类,进行合并,将bcolor所在类与acolor所在类进行同步
			color[bcolor] = acolor + acolor % 2 * 2 - 1;//color[bcolor](原值为0)更新为与acolor相异的另一色
			color[bcolor + bcolor % 2 * 2 - 1] = acolor;//color[与bcolor相异的另一色](原值为0)更新为acolor
		}
	}
	printf("1");
	return 0;
}

测试结果:
https://dsa.cs.tsinghua.edu.cn/oj/result/269e01a467fc75e5cfdd3b9355af33cd7beaa8e3.html

参考文章:
https://blog.csdn.net/qiang_____0712/article/details/87923838

2022/5/26更新:写得什么鬼,我自己都看不懂。。。
并查集是不断合并集合,本题的目的就是能否在满足条件的情况下将所有村子划分到两个集合(波段)中。
n个小镇初始视为n个集合,{1},{2},……,{n}
但是输入a,b只能知道a,b属于不同集合,无法进行合并,所以把集合扩充为{1},{非1},{2},{非2},……,{n},{非n}。
输入a,b,则 {b} 与 {非a} 合并, {非b} 与 {a} 合并。
若 {i} 与 {非i} 被合并到了同一个集合则表示出现冲突,划分失败。
染色只是一种实现方式而已(反而搞得复杂化了)

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值