二分图
如果一张无向图的 n n n ( n ≥ 2 ) (n≥2) ( n ≥ 2 ) 个节点可以分成 A , B A,B A , B 两个非空集合,其中 A ⋂ B A \bigcap B A ⋂ B 为空,并且在同一集合内的点之间都没有边相连,那么称这张无向图为一张二分图。 A , B A,B A , B 分别称为二分图的左部和右部。
二分图判定
无向图是二分图 ⇔ ⇔ ⇔ 图中无奇环(长度为奇数的环)
使用染色法,一个顶点涂黑色,另一个顶点涂白色,若搜到颜色不相符则不是二分图,否则是;
bool dfs_ ( int u, int color) {
c[ u] = color;
for ( int i= head[ u] ; ~ i; i= e[ i] . nxt) {
int v= e[ i] . v;
if ( c[ v] && c[ v] == color) return false ;
if ( ! c[ v] && ! dfs_ ( v, 3 - color) ) return false ;
}
return true ;
}
inline pd_ ( ) {
memset ( c, 0 , sizeof ( c) ) ;
for ( int i= 1 ; i<= n; ++ i) {
if ( ! c[ i] && ! dfs_ ( i, 1 ) ) return false ;
}
return true ;
}
#include <bits/stdc++.h>
using namespace std;
#define maxn 20010
#define maxm 100010
int n, m, f[ maxn<< 1 ] ;
struct node {
int x, y, z;
} e[ maxm] ;
inline bool cmp_ ( node aa, node bb) {
return aa. z > bb. z;
}
int find_ ( int x) {
if ( f[ x] == x) return x;
return f[ x] = find_ ( f[ x] ) ;
}
void readda_ ( ) {
n= read_ ( ) ; m= read_ ( ) ;
for ( int i= 1 ; i<= m; ++ i) {
e[ i] . x= read_ ( ) ; e[ i] . y= read_ ( ) ; e[ i] . z= read_ ( ) ;
} sort ( e+ 1 , e+ m+ 1 , cmp_) ;
for ( int i= 0 ; i<= ( n<< 1 ) ; ++ i) f[ i] = i;
for ( int i= 1 ; i<= m; ++ i) {
int x= find_ ( e[ i] . x) , y= find_ ( e[ i] . y) ;
if ( x== y) {
printf ( "%d" , e[ i] . z) ; return ; }
int xx= find_ ( e[ i] . x+ n) , yy= find_ ( e[ i] . y+ n) ;
f[ x] = yy; f[ y] = xx;
}
printf ( "0" ) ;
}
也可以用二分 + + + 二分图判定来做
二分最小值,将怒气值大于 m i d mid m i d 的两人连边,看能否将两人分开,也就是能否形成二分图
#include <bits/stdc++.h>
using namespace std;
#define maxn 20010
#define maxm 100010
int n, m, size= 0 , head[ maxn] , vis[ maxn] ;
struct node {
int x, y, z;
} AKIOI[ maxm] ;
struct edge {
int v, nxt;
} e[ maxm<< 1 ] ;
inline bool cmp_ ( node aa, node bb) {
return aa. z > bb. z;
}
inline void add_ ( int u, int v) {
e[ ++ size] . v= v;
e[ size] . nxt= head[ u] ;
head[ u] = size;
}
bool dfs_ ( int u, int color) {
vis[ u] = color;
for ( int i= head[ u] ; ~ i; i= e[ i] . nxt) {
int v= e[ i] . v;
if ( vis[ v] == color) return false ;
if ( vis[ v] == - 1 && ! dfs_ ( v, color^ 1 ) ) return false ;
}
return true ;
}
inline bool pd_ ( int now) {
memset ( head, - 1 , sizeof ( head) ) ;
size= 0 ;
for ( int i= 1 ; i<= m; ++ i) {
if ( AKIOI[ i] . z<= now) break ;
add_ ( AKIOI[ i] . x, AKIOI[ i] . y) ;
add_ ( AKIOI[ i] . y, AKIOI[ i] . x) ;
}
memset ( vis, - 1 , sizeof ( vis) ) ;
for ( int i= 1 ; i<= n; ++ i) {
if ( vis[ i] == - 1 && ! dfs_ ( i, 1 ) ) return false ;
}
return true ;
}
void readda_ ( ) {
n= read_ ( ) ; m= read_ ( ) ;
for ( int i= 1 ; i<= m; ++ i) {
AKIOI[ i] . x= read_ ( ) ; AKIOI[ i] . y= read_ ( ) ; AKIOI[ i] . z= read_ ( ) ;
} sort ( AKIOI+ 1 , AKIOI+ 1 + m, cmp_) ;
int l= 0 , r= AKIOI[ 1 ] . z, mid;
while ( l<= r) {
mid= ( l+ r) >> 1 ;
if ( pd_ ( mid) ) r= mid- 1 ;
else l= mid+ 1 ;
}
printf ( "%d" , l) ;
}
二分图最大匹配
图的匹配定义
两条边都没有公共端点的边的集合被称为图的一组匹配。
即每个点只有一条连边
二分图最大匹配
在二分图中,包含边数最多的一组匹配被称为二分图的最大匹配
其他相关定义
对于任意一组匹配 S S S (边集),属于 S S S 的边被称为匹配边,不属于 S S S 的边被称为非匹配边。
匹配边的端点被称为匹配点,其他节点被称为非匹配点。
如果二分图中存在一条连接两个非匹配点的路径 p a t h path p a t h ,使得非匹配边与匹配边在 p a t h path p a t h 上交替出现,那么称 p a t h path p a t h 是匹配 S S