201971010140-魏瑾川 實驗二 軟體工程個人專案—01揹包問題專案報告
定義
二分圖又稱作二部圖,是圖論中的一種特殊模型。設G=(V,E)是一個無向圖,如果頂點V可分割為互不相交的子集(A,B),並且圖中每條邊(i,j)所關聯的兩個頂點i和j分別屬於這兩個不同的頂點集\((i\in A,j\in B)\),則稱圖G為一個二分圖。
就是說無向圖G中所有點劃分為兩個集合,並且任意一條邊上的兩個點不能屬於同一集合。
判斷方法
在dfs的過程中進行染色,每條邊上的兩個點只能一個染0,一個染1,能滿足要求即是二分圖,不能則不是二分圖,注意至少要有兩個點。
參考程式碼
#include<bits/stdc++.h> using namespace std; const int N=1e5; int f[N]; vector<int>g[N]; int n,m;//點數,邊數 bool dfs(int x,int c){ f[x]=c; int len=g[x].size(),to; for(int i=0;i<len;++i){ to=g[x][i]; if(f[to]==c)return false; else if(f[to]==-1) if(!dfs(to,c^1))return false; } return true; } int main(){ scanf("%d%d",&n,&m); int a,b; for(int i=0;i<m;++i){ scanf("%d%d",&a,&b); g[a].push_back(b); g[b].push_back(a); } //建圖 if(n==1){printf("Not a bipartite graph\n");return 0;} for(int i=1;i<=n;++i)f[i]=-1; bool flag=0; for(int i=1;i<=n;++i){ if(f[i]==-1&&!dfs(i,0)){flag=1;printf("Not a bipartite graph\n");break;} } if(!flag)printf("It's a bipartite graph\n"); return 0; }
最大匹配
給定一個二分圖G,在G的一個子圖M中,M的邊集中的任意兩條邊都不依附於同一個頂點,則稱M是一個匹配。選擇這樣的邊數最大的子集稱為圖的最大匹配問題(maximal matching problem)
如果一個匹配中,圖中的每個頂點都和圖中某條邊相關聯,則稱此匹配為完全匹配,也稱作完備匹配。
簡單總結一下:
1.在一個迴圈中依次給每個男生找物件(打個比方)。
2.依次訪問每個可能成功的女生。
3.如果這名女生是在本輪迴圈中第一次訪問到並且也還沒物件,那麼匹配成功。
4.如果這名女生是在本輪迴圈中第一次訪問到但是有物件男2了,那麼我們可以試著(如果失敗的話就為當前男生找其他女生,男2不受影響)為男2找其他物件,這樣就又來到了第一步。
5.如果這名女生是第二次訪問到,那麼她跟當前男生肯定是沒戲了。(如果接著訪問,在程式中體現為無限遞迴)
6.如果迴圈結構中的男生匹配完所有可能的女生都失敗了,那麼他就落單了。
例題:矩陣遊戲
思路
將行與列進行匹配,若某一行與某一列的交點為1,則該行與該列之間連有邊,可以發現行交換與列交換並不會改變最大匹配數(其實就是交換兩個點的順序而已,整個圖的結構沒有變化),只要最大匹配數為n就有解。
參考程式碼
#include<bits/stdc++.h> using namespace std; const int N=500; vector<int>node[N]; int t,n,a; int match[N],used[N]; bool dfs(int x){ int to,len=node[x].size(); for(int i=0;i<len;++i){ to=node[x][i]; if(!used[to]){ used[to]=1; if(!match[to]||dfs(match[to])){ match[to]=x; return true; } } } return false; } int ans; int main(){ scanf("%d",&t); while(t--){ ans=0; memset(match,0,sizeof(match)); scanf("%d",&n); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j){ scanf("%d",&a); if(a){ node[i].push_back(j+n); } } for(int i=1;i<=n;++i){ memset(used,0,sizeof(used)); if(dfs(i))++ans; } for(int i=1;i<=n;++i) node[i].clear(); if(ans==n) printf("Yes\n"); else printf("No\n"); } return 0; }