關於二分圖問題的總結

1、什麼是二分圖

可以把頂點分成X,Y兩個集合,且每個集合裏沒有相鄰的邊(相連)。


2、二分圖有哪些問題

2.1 二分圖的判定

     關於二分圖的判定,一般使用染色判斷法,即把邊兩端的定點顏色染成不同顏色觀察是否衝突。

    模板:

   

bool judge(int u){  
    for (int i=head[u];~i;i=e[i].nxt){  
        int v=e[i].to;  
        if (!col[v]){  
            col[v]=!col[u];  
            if (!judge(v)) return 0;  
        }  
        else if (col[v]==col[u])  
            return 0;  
    }  
    return 1;  
}  
if (judge(1)) return true;

2.2 二分圖匹配問題


2.2.1 二分圖最大匹配

採用匈牙利算法,注意頂點數/2,O(VE),有bfs和dfs兩個版本,對於稀疏圖bfs快,稠密圖差不多,dfs優點在於好寫。

bool dfs(int u){  
    for (int i=head[u];~i;i=e[i].nxt){  
        int v=e[i].to;  
        if (!vis[v]){  
            vis[v]=1;  
            if (link[v]==-1 || dfs(link[v])){  
                link[v]=u;  
                return 1;  
            }  
        }  
    }  
    return 0;  
}  
int match(){  
    int ans=0;  
    memset(link,-1,sizeof(link));  
    for (int i=1;i<=n;i++){  
        memset(vis,0,sizeof(vis));  
        if (dfs(i)) ans++;  
    }  
    return ans;  
}


2.2.2 二分圖完全匹配

完全匹配是一個驗證問題,只要把2.2.1的ans和頂點數/2相比即可。


2.2.3 二分圖帶權匹配

KM算法,O(n^3)。

// 最小費用最大流 KM算法 帶權二分圖匹配
// KM算法是求最大權值匹配,求最小權值匹配,只需要將所有邊權取負。
// 邊權之積最大 取對數
// S->{X} 權值爲0,容量爲1。
// {Y}->T 權值爲0,容量爲1。
// 原有的邊 權值不變,容量爲1。
// 鄰接矩陣 不適合稀疏圖
// 如果可以非完全匹配,引入頂點A,{X}->A 容量爲1,權值爲0.
// A->T 權值爲0,容量不小於|X|

const int ME=1010;
const int MV=100;
struct edge{
    int to,nxt,flow;
    db cost;
}e[ME];
int head[MV],cnt;
queue<int> q;
int cur[MV],pre[MV];
bool used[MV],sign[MV];
int flow,n,m;
db cost,dis[MV];
double p[16][1024];
bool spfa(int s,int t){
    memset(used,0,sizeof(used));
    memset(sign,0,sizeof(sign));
    memset(dis,0,sizeof(dis));
    used[s]=sign[s]=1;
    while (!q.empty()) q.pop();
    q.push(s);
    while (!q.empty()){
        int u=q.front();
        q.pop();
        used[u]=0;
        for (int i=head[u];~i;i=e[i].nxt){
            if (e[i].flow<1) continue;
            int v=e[i].to;
            db c=e[i].cost;
            if (!sign[v] || dis[v]>dis[u]+c){
                dis[v]=dis[u]+c;
                sign[v]=1;
                pre[v]=u;
                cur[v]=i;
                if (used[v]) continue;
                used[v]=1;
                q.push(v);
            }
        }
    }
    return sign[t];
}
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int flow,db cost){
    e[cnt].to=v, e[cnt].flow=flow, e[cnt].cost=cost;
    e[cnt].nxt=head[u], head[u]=cnt++;

    e[cnt].to=u, e[cnt].flow=0, e[cnt].cost=-cost;
    e[cnt].nxt=head[v], head[v]=cnt++;
}
void solve(int s,int t){
    flow=cost=0;
    while (spfa(s,t)){
        int tmp=t;
        int now=inf;
        while (tmp!=s){
            now=min(now,e[cur[tmp]].flow);
            tmp=pre[tmp];
        }
        flow+=now;
        tmp=t;
        while (tmp!=s){
            int id=cur[tmp];
            cost+=now*e[id].cost;
            e[id].flow-=now;
            e[id^1].flow+=now;
            tmp=pre[tmp];
        }
    }
}
db getcost(){
    return cost;
}

3、可以轉化成二分圖的問題


3.1 最小路徑覆蓋

頂點數-最大匹配。


3.2 最小頂點覆蓋

最大匹配


3.3 最小邊覆蓋

  最大匹配


3.4 最大獨立集

頂點數-最大匹配。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章