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} 被合并到了同一个集合则表示出现冲突,划分失败。
染色只是一种实现方式而已(反而搞得复杂化了)