1. 程式人生 > 其它 >201971010140-魏瑾川 實驗二 軟體工程個人專案—01揹包問題專案報告

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;
}