[算法] 二分图判定
二分图判定
定义
简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。
——摘自度娘
还是不懂的可以查阅百度百科,上面有例子。
判定
在一张无向图中,若图中不存在长度为奇数的环,则该图是二分图。
简单证明:
若存在长度为奇数的环,环中任意一点为A,属于集合1,则环内与A相邻的两个顶点B,C都会被分到与A不同的集合2中。然后其中一个点的相邻的点C(还有一点是A就不用考虑了)就也分到集合1中,若A,B,C(可能有更多点参与,情况与这样类似)形成一个长度为奇数的环,则会发生冲突,因为A,C在一个集合, 不满足定义。若仅仅是一个长度为偶数的环,也是可以的,若下图所示。
分成集合A(SetA)与集合B(SetB)。
可以使用染色法来判断二分图。
给相邻的点染上不同的颜色,看是否会发生冲突(与相邻的点颜色相同)。
C++代码
bool Paint(int now, int color) {
bool flag = true;
col[now] = color;
int SIZ = v[now].size();
for(int i = 0; i < SIZ; i++) {
int next = v[now][i];
if(!col[next])
flag &= Paint(next, 3 - color);
else if(col[next] == color)
return false;
}
return flag;
}
bool Build() {
bool flag = true;
memset(col, 0, sizeof(col));
for(int i = 1; i <= n; i++)
if(!col[i])
flag &= Paint(i, 1);
return flag;
}
NOIP2010 关押罪犯
题目描述
S 城现有两座监狱,一共关押着\(N\)名罪犯,编号分别为\(1-N\)。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为\(c\)的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为\(c\)的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到 S 城 Z 市长那里。公务繁忙的 Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在详细考察了\(N\)名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。
那么,应如何分配罪犯,才能使 Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?
输入格式
每行中两个数之间用一个空格隔开。第一行为两个正整数\(N,M\),分别表示罪犯的数目以及存在仇恨的罪犯对数。接下来的\(M\)行每行为三个正整数\(a_j,b_j,c_j\),表示\(a_j\)号和\(b_j\)号罪犯之间存在仇恨,其怨气值为\(c_j\)。数据保证\(1<a_j\leq b_j\leq N, 0 < c_j\leq 10^9\),且每对罪犯组合只出现一次。
输出格式
共\(1\)行,为 Z 市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出 0。
输入输出样例
输入
4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884
输出
3512
说明/提示
【输入输出样例说明】罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件影响力是 35123512(由 22 号和 33 号罪犯引发)。其他任何分法都不会比这个分法更优。
【数据范围】
对于\(30\%\)的数据有\(N\leq 15\)。
对于\(70\%\)的数据有\(N\leq 2000,M\leq 50000\)。
对于\(100\%\)的数据有\(N\leq 20000,M\leq 100000\)。
思路
可以二分答案。
对于大于mid的边,删除该边,判断是否是二分图。
如果是,那么mid就可以为答案。否则就不是。
代码
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
void Quick_Read(int &N) {
N = 0;
char c = getchar();
int op = 1;
while(c < '0' || c > '9') {
if(c == '-')
op = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
N = (N << 1) + (N << 3) + c - 48;
c = getchar();
}
N *= op;
}
const int MAXN = 2e4 + 5;
struct Node {
int To, Hate;
Node() { To = Hate = 0; }
Node(int T, int H) {
To = T;
Hate = H;
}
};
vector<Node> v[MAXN];
int n, m;
int col[MAXN];
void Read() {
int A, B, C;
Quick_Read(n);
Quick_Read(m);
for(int i = 1; i <= m; i++) {
Quick_Read(A);
Quick_Read(B);
Quick_Read(C);
v[A].push_back(Node(B, C));
v[B].push_back(Node(A, C));
}
}
bool Paint(int now, int color, int maxn) {
bool flag = true;
col[now] = color;
int SIZ = v[now].size();
for(int i = 0; i < SIZ; i++) {
if(v[now][i].Hate <= maxn)
continue;
int next = v[now][i].To;
if(!col[next])
flag &= Paint(next, 3 - color, maxn);
else if(col[next] == color)
return false;
}
return flag;
}
bool Build(int maxn) {
bool flag = true;
memset(col, 0, sizeof(col));
for(int i = 1; i <= n; i++)
if(!col[i])
flag &= Paint(i, 1, maxn);
return flag;
}
void Dich() {
int l = 0, r = 1e9;
while(l < r) {
int mid = (l + r) >> 1;
if(Build(mid))
r = mid;
else
l = mid + 1;
}
printf("%d", l);
}
int main() {
Read();
Dich();
return 0;
}