20211011二分图匹配+判定

  • 2021 年 10 月 11 日
  • 笔记

今天又是摸鱼的一天,就复习了一下数据结构,然后树剖板子打炸了,线段树2调疯了,tarjan也搞没了。

还有就是学了一下二分图,之前假期发了学案懒得看,今天就跑过去听,感觉还不错。

1.二分图是什么:

二分图又称作二部图,是图论中的一种。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

简单来说,就是能把定点分成两部分,任意两点间有且只有一条路径。

至于二分图的判定,我们用深度搜索染色来实现。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m,color[205];
 5 vector<int> node[205];//领接表存图
 6 
 7 bool dfs(int v,int c){//搜索染色
 8     color[v]=c;
 9     for(int i=0;i<node[v].size();i++){
10         if(color[node[v][i]]==c){//相连的点颜色必须不同
11             return 0;
12         }else if(color[node[v][i]]==0&&!dfs(node[v][i],-c)){//还未染色切染了色也没有问题
13             return 0;
14         }
15     }
16     return 1;
17 }
18 int main(){
19     int u,v;
20     cin>>n>>m;
21     for(int i=0;i<m;i++){
22         cin>>u>>v;
23         node[u].push_back(v);
24         node[v].push_back(u);
25     }
26     
27     for(int i=0;i<n;i++){
28         if(color[i]==0){//从每一个点开始
29             if(!dfs(i,1)){
30                 cout<<"NO"<<endl;
31                 return 0;
32             }
33         }
34     }
35     cout<<"YES"<<endl;
36     
37     
38     return 0;
39 }

例题:关押罪犯//www.luogu.com.cn/problem/P1525

思路:二分答案+染色搜索判定

先排序按照暴力事件的大小升序排列,然后二分一个答案,如果MID满足条件那么大于mid的都可以,接下来就向左半边二分。

我们每找到一个mid的值就用一个check函数判断是否合法。判断方式就是,把大于mid的边存入领接表,再用染色判断大于他的边能否形成一个二分图。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int N=20010;
  5 const int M=100010;
  6 int n,m,color[N];
  7 bool flag;
  8 vector<int> e[N];
  9 struct edges{
 10     int x,y,v;
 11 }a[M]; 
 12 
 13 bool cmp(edges a,edges b){
 14     return a.v<b.v;
 15 }
 16 
 17 //void dfs(int u,int c){
 18 //    color[u]=c;
 19 //    for(int i=0;i<e[i].size();i++){
 20 //        int v=e[u][i];
 21 //         if(!color[v]){
 22 //            dfs(v,-c);
 23 //        }else 
 24 //        if(color[v]==c){
 25 //            flag=0;
 26 //        }
 27 //    }
 28 //}
 29 void dfs(int u, int c)  //染色  
 30 { 
 31     color[u]=c; 
 32     for(int i=0;i<e[u].size();i++) //枚举从u出
 33   { 
 34         int v=e[u][i];             //v是u的相邻
 35         if(!color[v]) dfs(v,-c);             //继续染色  
 36         else if(color[v]==c) flag=false;  //颜色
 37     } 
 38 } 
 39  
 40 
 41 //bool check(int pos){
 42 //    for(int i=1;i<=n;i++) e[i].clear();
 43 //    for(int i=pos+1;i<=m;i++){
 44 //        e[a[i].x].push_back(a[i].y);
 45 //        e[a[i].y].push_back(a[i].x);
 46 //    }
 47 //    flag=true;
 48 //    memset(color,0,sizeof(color));
 49 //    for(int i=1;i<=n;i++){
 50 //        if(!color[i]){
 51 //            dfs(i,1);
 52 //            if(!flag) return false;
 53 //        }
 54 //    } 
 55 //    return true;
 56 //}
 57 
 58 bool check(int pos)  //判断是否合法:能构成
 59 { 
 60     for(int i=1;i<=n;i++) e[i].clear();  //
 61     for(int i=pos+1;i<=m;i++)            //
 62   { 
 63         e[a[i].x].push_back(a[i].y); 
 64         e[a[i].y].push_back(a[i].x); 
 65     } 
 66     flag=true; 
 67     memset(color,0,sizeof color); 
 68     for(int i=1;i<=n;i++)                //
 69         if(!color[i]) 
 70     { 
 71             dfs(i,1); 
 72             if(!flag) return false; 
 73         } 
 74     return true; 
 75 } 
 76 int main()
 77 {
 78     cin>>n>>m;
 79     for(int i=1;i<=m;i++){
 80         cin>>a[i].x>>a[i].y>>a[i].v;
 81     }
 82     sort(a+1,a+m+1,cmp);
 83 
 84     int l=0;
 85     int r=m;
 86     int mid;
 87 //    while(l<r){
 88 //         mid=(l+r)>>1;
 89 //        if(check(mid)){
 90 //            r=mid;
 91 //            cout<<r<<' '<<123<<endl;
 92 //        }else l=mid+1,cout<<l<<' '<<321<<endl;
 93 //    }
 94     while(l<r) 
 95   { 
 96         mid=(l+r)>>1; 
 97         if(check(mid)) 
 98       r=mid;        
 99         else 
100       l=mid+1;      
101     } 
102     if(m==1){
103         cout<<0<<endl;
104     } else{
105     
106         cout<<a[l].v<<endl;
107     }
108     return 0;
109 }