关于二分图问题的总结

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 最大独立集

顶点数-最大匹配。

你可能感兴趣的:(关于二分图问题的总结)