二分图当且仅当图中不存在奇数长度的环
根据上面的定理有二分图染色判定,复杂度O(N+M)
1 void dfs(int x, int color) { 2 v[x]=color; 3 for(int i=head[x];i;i=nex[i]){ 4 int y=ver[i]; 5 if(!v[y]) {if(!dfs(y,3-color)) return false;} 6 else if(v[y]==color) return false; 7 } 8 return true; 9 } 10 11 int main(){ 12 bool flag=true; 13 for(int i=1;i<=n;i++) if(!v[i]) if(!dfs(i,1)) flag=false; 14 }
关于二分图匹配的算法,最基础的就是匈牙利算法,每次找一个点,看看他是否有增广路,使匹配增加,复杂度O(N*M)
1 bool dfs(int x){ 2 for(int i=head[x];i;i=nex[i]){ 3 int y=ver[i]; 4 if(!v[y]){ 5 v[y]=1; 6 if(!m[y] || dfs(m[y])){ 7 m[y]=x; 8 return true; 9 } 10 } 11 } 12 } 13 for(int i=1;i<=n;i++){ 14 memset(v,0,sizeof(v)); 15 if(dfs(i)) ans++; 16 }
HK算法是每次用M的复杂度匹配可以匹配的点,这样不再用N次,而只需要√N次即可(原因是最坏情况下N个点都匹配,每次匹配√N个匹配√N次,因为每次匹配是在上一次匹配的基础上匹配,所以匹配次数不能大于上一次,只有√N*√N才会每次用M复杂度,如果1*N只需要一次M,或者N*1也是一个M,所以最坏情况M的最坏迭代次数是√N)
1 bool find(int x){ 2 /* 找寻所有深度右边是左边+1的点,这样就相当于找增广路,看看增广路能否增广 */ 3 for(int i=0;i<G[x].size();i++){ 4 int y=G[x][i]; 5 if(!vis[y] && dy[y]==dx[x]+1){ 6 vis[y]=true; 7 if(!my[y] || find(my[y])){mx[x]=y;my[y]=x;return true;} 8 } 9 } 10 return false; 11 } 12 13 int match(){ 14 /* 初始化 */ 15 memset(mx,0,sizeof(mx)); 16 memset(my,0,sizeof(my)); 17 int ans=0; 18 while(true){ 19 /* 初始化 */ 20 bool flag=false; 21 while(q.size()) q.pop(); 22 memset(dx,0,sizeof(dx)); 23 memset(dy,0,sizeof(dy)); 24 /* 将所有未匹配的左边点加入队列 */ 25 fore(i,1,nx) if(!mx[P[i]]) q.push(P[i]); 26 /* 将所有非匹配点进行BFS,将所有点按层次编号 */ 27 while(q.size()){ 28 int x=q.front();q.pop(); 29 for(int i=0;i<G[x].size();i++){ 30 int y=G[x][i]; 31 if(!dy[y]){ 32 dy[y] = dx[x] + 1; 33 /* 凡是已匹配的将被匹配的点继续层次编号 */ 34 if(my[y]) dx[my[y]]=dy[y]+1,q.push(my[y]); 35 else flag=true; 36 } 37 } 38 } 39 if(!flag) break;//确保有一个点是空匹配点 40 memset(vis,0,sizeof(vis)); 41 fore(i,1,nx) if(!mx[P[i]] && find(P[i])) ans++; 42 } 43 return ans; 44 }
1 vector<int>G[N]; 2 int nx,ny; 3 int mx[N],my[N]; 4 queue<int>q; 5 int dx[N],dy[N]; 6 bool vis[N];