update:2019/09/25 重新将两篇二分图的学习报告整合
一,二分图的定义
对于一个图上的所有节点能够分成两个集合且保证边仅存在在两个集合之间,集合内部没有边,这样的图叫做二分图。
二,二分图的一些性质(一些比较重要的性质)
1,二分图没有奇环
2,二分图的最小顶点覆盖
定义:若选择一个点即覆盖了所有与这个点相连的边,最小点覆盖就是选择最少的点覆盖所有的边。
定理:二分图的最小顶点覆盖数=二分图的最大匹配数
3,二分图的最大独立集
定义:选取一些点使得任何两个点之间没有边相连,能选取的最多的顶点称为最大独立集
定理:二分图的最大独立集=二分图的顶点数-二分图的最小顶点覆盖数
三,二分图的判断方法—染色法
算法流程:即对于每条边(u,v)如果v没有染色就染上与u相反的颜色,如果u和v颜色相同,则证明不是二分图,
若能完成所有的染色则证明是一个二分图。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 6 using namespace std; 7 8 struct node 9 { 10 int ed,nxt; 11 }; 12 node edge[2333]; 13 int n,m,first[2333],cnt; 14 int color[2333]; 15 bool flag; 16 17 inline void add_edge(int s,int e) 18 { 19 cnt++; 20 edge[cnt].ed=e; 21 edge[cnt].nxt=first[s]; 22 first[s]=cnt; 23 return; 24 } 25 26 inline void pd(int pos,int c) 27 { 28 color[pos]=c; 29 for(int i=first[pos];i;i=edge[i].nxt) 30 { 31 int e=edge[i].ed; 32 if(color[pos]==color[e]) {flag=false;return;} 33 else if(color[e]==0) pd(e,-c); 34 } 35 } 36 37 int main() 38 { 39 scanf("%d%d",&n,&m); 40 for(int i=1;i<=m;i++) 41 { 42 int s,e; 43 scanf("%d%d",&s,&e); 44 add_edge(s,e); 45 add_edge(e,s); 46 } 47 flag=true; 48 memset(color,0,sizeof(color)); 49 for(int i=1;i<=n;i++) 50 { 51 if(!color[i]) pd(i,1); 52 if(!flag) 53 { 54 printf("NO"); 55 return 0; 56 } 57 } 58 printf("YES"); 59 return 0; 60 }
四,二分图的匹配问题
匹配:一个左端点+一条边+一个右端点 (且左端点和右端点只能在一个匹配里) 称为一个匹配
1,完美匹配
即二分图的左右所有端点都被匹配了。
2,最大匹配—匈牙利算法
算法过程:寻找增广路径
算法流程:
从左侧集合中的第一个点开始寻找匹配
如果某条边的中点没有被匹配过就匹配上,否则就寻找是否存在增广路径。
寻找增广路径的过程其实是一个再匹配的过程,让已经配对的左集合端点暂时取消匹配而去找下一个能匹配的右集合端点
如果能找到就存在增广路径,否则不存在。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 2005 6 7 using namespace std; 8 9 struct node 10 { 11 int ed,nxt; 12 }; 13 node edge[maxn*maxn]; 14 int n,m,e,first[maxn],ans,cnt; 15 bool used[maxn]; 16 int match[maxn]; 17 18 inline void add_edge(int st,int ed) 19 { 20 cnt++; 21 edge[cnt].ed=ed; 22 edge[cnt].nxt=first[st]; 23 first[st]=cnt; 24 return; 25 } 26 27 inline bool dfs(int k) 28 { 29 for(int i=first[k];i!=0;i=edge[i].nxt) 30 { 31 int e=edge[i].ed; 32 if(!used[e]) 33 { 34 used[e]=true; 35 if(!match[e]||dfs(match[e])) 36 { 37 match[e]=k; 38 return true; 39 } 40 } 41 } 42 return false; 43 } 44 45 int main() 46 { 47 scanf("%d%d%d",&n,&m,&e); 48 for(int i=1;i<=e;i++) 49 { 50 int st,ed; 51 scanf("%d%d",&st,&ed); 52 if(st<=n&&ed<=m) add_edge(st,ed); 53 } 54 for(int i=1;i<=n;i++) 55 { 56 memset(used,false,sizeof(used)); 57 if(dfs(i)) ans++; 58 } 59 printf("%d",ans); 60 return 0; 61 }