二分圖

說說二分圖,其實圖論的題難點不在用算法,難在如何建圖,只有圖建好了,剩下的就簡單了,在這說說求二分圖的算法,即匈牙利算法,其實一點都不難,也很好理解拿筆寫寫就行了.

二分圖最大匹配----匈牙利算法

重要的一點就是看出來了用二分圖做,然后就是建圖了,再然后適當修改Find函數就行了.

int n,m;
int link[1001];
bool vis[1001];
vector<int>data[1001];
bool Find(int x)
{
    for(int i=0;i<data[x].size();i++){
        int m=data[x][i];
        if(!vis[m]){
            vis[m] = true;
            if(!link[m] || Find(link[m])){
                link[m] = x;
                link[x] = m;
                return true;
            }
        }
    }
    return false;
}

模板題
AC代碼:

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define CLR(x) memset(x,0,sizeof(x))
int n,m;
int link[1001];
bool vis[1001];
vector<int>data[1001];
bool Find(int x)
{
    for(int i=0;i<data[x].size();i++){
        int m=data[x][i];
        if(!vis[m]){
            vis[m] = true;
            if(!link[m] || Find(link[m])){
                link[m] = x;
                link[x] = m;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    CLR(link);
    int ans=0;
    for(int i=0;i<m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        data[u].push_back(v);
        data[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
    {
        CLR(vis);
        if(!link[i] && Find(i))   //記住判斷的先后邏輯順序!!!
            ans++;
    }
    printf("%d\n", ans);
}

這里有些重要的定理,有許多題經過建圖后發現就是求這些,故常常配合著這個二分圖來運算需要記住!!!
(通過一些小的改變即可達到要求)
定理:
定理1:最大匹配數M = 最小點覆蓋數
定理2:最大獨立集 = 頂點數 - 最大匹配數
定理3:有向圖最小路徑覆蓋數 = 頂點數 - 最大匹配數
定理4:無向圖最小路徑覆蓋數 = 頂點數 - 最大匹配數/2
(因為處理過兩次)
對以上名詞的一些解釋:
最大匹配數:最大匹配的匹配邊的數目
最小點覆蓋數:選取最少的點,使任意一條邊至少有一個端點被選擇
最大獨立集:選取最多的點,使任意所選兩點均不相連
最小路徑覆蓋數:對于一個 DAG (有向無環圖),選取最少條路徑,使得每個頂點屬于且僅屬于一條路徑。路徑長可以為 0 (即單個點).
證明略.

二分圖判定----染色法
模板題在此

染色法判斷是否是二分圖.

AC代碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define CLR(x) memset(x,0,sizeof(x))
const int maxn=1e4+5;
int cas=1;
bool flag;
int n,m;
bool vis[maxn][maxn];   //vis[i][j] 表示 i 到 j 是否相連過.是的話數組值為1,否則為 0 .
vector<int>ve[maxn];
int color[maxn];
void dfs(int x,int col)
{
    if(!flag) return ;   //flag=false, 后面就都沒有必要再搜下去了.
    if(!color[x]) color[x]=col;  //如果該點沒有被染色,就染上.
    else if(color[x]!=col){   //如果遇到將要染色的點不等于將要被染的色,則結束dfs,不是二分圖.
        flag=false;
        return ;
    }
    for(int i=0;i<ve[x].size();i++)
    {
        int next=ve[x][i];
        if(!vis[x][next] && !vis[next][x]){
            vis[x][next]=1;
            dfs(next,3-col);
        }
    }
}
int main()
{
    int t;
    cin >> t;
    while(t--){
       flag=true;
       scanf("%d %d",&n,&m);
       CLR(color);
       CLR(vis);
       for(int i=1;i<=n;i++)
           ve[i].clear();
       for(int i=0;i<m;i++){
            int u,v;
            scanf("%d %d",&u,&v);
            ve[u].push_back(v);
            ve[v].push_back(u);
        }
        for(int i=1;i<=n;i++)
        {
            if(!color[i]) dfs(i,1);    //循環染色.  分別左邊染1,右邊染2 .
        }
        if(flag) printf("Correct\n");
        else
            printf("Wrong\n");
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 定義## 記圖 G = (V, E) 最大流問題##### 記每條邊所能傳輸的最大流量為 c(e) 記每條邊所能傳...
    MrGopher閱讀 985評論 0 1
  • 二分圖又稱作二部圖,是圖論中的一種特殊模型。 設G=(V,E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(...
    Myth52125閱讀 10,307評論 0 4
  • 二分圖判定: 題目鏈接:二分圖判定 dfs: 最大匹配: 題目鏈接:最大匹配-匈牙利算法 dfs: 二維最大匹配:...
    fo0Old閱讀 567評論 0 1
  • 題目描述 給定一個二分圖,結點個數分別為n,m,邊數為e,求二分圖最大匹配數 輸入輸出格式 輸入格式第一行,n,m...
    Ricardo_Y_Li閱讀 335評論 0 1
  • 分別總是會有一些猝不及防。 與媽媽告別的時候,和她笑著揮揮手。 “路上注意安全。” “嗯知道啦。” “包里裝的堅果...
    車小花閱讀 614評論 0 2