1. 程式人生 > 資訊 >平均每天銷售 1000 輛,超越特斯拉,五菱巨集光 MINIEV 今年上半年銷量達 182767 輛

平均每天銷售 1000 輛,超越特斯拉,五菱巨集光 MINIEV 今年上半年銷量達 182767 輛

二分圖:在一個圖中,如果圖中的點可以被分為兩個部分,兩部分之間有若干條邊相連,且每個部分的點之間無邊相連,則該圖是一個二分圖。由此可以很容易知道,二分圖絕對是一個無環圖。

如上圖,圖一是一個二分圖,但從外表並不明顯,可以轉換成圖二的樣式。圖三是這個二分圖的一個匹配(紅線部分),圖四則是它的最大匹配,也是完美匹配。

#include <stdio.h>
#include <vector>
#include <string.h>
using namespace std;
const int N = 205;

vector<int>G[N];
int n,m;
int vis[N],pre[N]; //標記  存男朋友
int c[N]; //顏色

//用染色法判斷這個圖是否是二分圖
bool Dfs(int u,int colour){
    c[u] = colour;
    for(int i = 0;i < G[u].size();i++){
        int v = G[u][i];
        if(c[v] == 0 && Dfs(v,3-colour)){
            return true;
        }else if(c[v] != 3-colour) {
            printf("No\n");
            return true;
        }
    }
    return false;
}
//用匈牙利演算法求出最大匹配數
bool dfs(int u){
    for(int i = 0;i <G[u].size();i++){
        int v = G[u][i];
        if(!vis[v]){
            vis[v] = 1;
            if(!pre[v] || dfs(pre[v])){//如果前一個可以移動也行
                pre[v] = u;//記錄前一個
                return true;
            }
        }
    }
    return false;
}
void solve(){
    for(int i = 1;i <= n;i++){    //染色
        if(c[i] == 0 && Dfs(i,1)){
            return;
        }
    }
    int ans = 0;
    for(int i = 1;i <= n;i++){ //匈牙利
        memset(vis,0,sizeof vis);
        if(dfs(i)) ans++;
    }
    printf("%d\n",ans);
}
void init(){
    for(int i = 0;i < N;i++){
        G[i].clear();
    }
    memset(pre,0,sizeof pre);
    memset(c,0,sizeof c);
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        init();
        while(m--){
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
        }
        solve();
    }
    return 0;
}

最大匹配數:最大匹配的匹配邊的數目

最小點覆蓋數:選取最少的點,使任意一條邊至少有一個端點被選擇

最大獨立數:選取最多的點,使任意所選兩點均不相連

最小路徑覆蓋數:對於一個 DAG(有向無環圖),選取最少條路徑,使得每個頂點屬於且僅屬於一條路徑。路徑長可以為 0(即單個點)。

定理1:最大匹配數 = 最小點覆蓋數(這是 Konig 定理)

定理2:最大匹配數 = 最大獨立數

定理3:最小路徑覆蓋數 = 頂點數 - 最大匹配數