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 }