二分图复习笔记

概念

匹配:一个边的集合,任何两边都没有公共点。
最大匹配:匹配边数最多的匹配。
完美匹配:所有顶点都是匹配点。
最小点覆盖:用最少的点,让每条边都至少和其中一个点相关联。
最小边覆盖:用尽量少的不相交简单路径覆盖有向无环图G的所有顶点。
最大独立集:在n个点的图G中选出两两之间没有边的尽量多的m个点,这m个点所组成的集合。

关系

最小点覆盖=最大匹配数
最小边覆盖=顶点数-最小顶点覆盖(最大匹配)
顶点数=二分图中最大独立集+最小顶点覆盖(最大匹配)
最大独立集的顶点数量=所有顶点数-最小点覆盖
最大团中顶点数量 = 补图的最大独立集中顶点数量

例题

出处:http://blog.csdn.net/u012294939/article/details/43763005
(时间有限不知道这些题以后会不会做,在这先写上一句话题解)

HDU 1083&&POJ 1469

一道Hungary的裸题
这道题必须要用邻接矩阵,否则要MLE。

注意:

1、Hungary(mch[i])
2、vis[i]=1; 单指一边,不能写在for的外面

//MLE 
#include<cstdio>
#include<cstring>
using namespace std;
//int to[M],nxt[M],head[PO],etot;
bool vis[305],ed[105][305];int mch[305];
int p,n; 
bool Hungary(int u)
{
    //for(int i=head[u];i;i=nxt[i])
    for(int i=1;i<=n;i++)
    if(ed[u][i]){
        if(vis[i]) continue;
        vis[i]=1;
        if(!mch[i]||Hungary(mch[i])){
            mch[i]=u;
            return 1;
        }
    }
    return 0;
}
void init()
{
    memset(mch,0,sizeof(mch));
    memset(ed,0,sizeof(ed));
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&p,&n);
        for(int i=1;i<=p;i++){//课程 
            int k;
            scanf("%d",&k);
            for(int j=1;j<=k;j++){
                int stu;
                scanf("%d",&stu);
                ed[i][stu]=1;
            }
        }
        bool MK=0;
        for(int i=1;i<=p;i++){
            memset(vis,0,sizeof(vis));
            if(!Hungary(i)){
                MK=1;break;
            }
        }
        if(!MK) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
HDU 1151/POJ1422 DAG的最小不相交路径覆盖

翻了好多篇博客就看懂了这篇:
http://www.cnblogs.com/icode-girl/p/5418461.html
用自己的语言简述一下:若一个点不是结尾节点,那么它在二分图中一定还连向了别的节点(也就是它和那个点形成了一个匹配)。在二分图中求最大匹配也就是求有多少个点不是结尾节点。
所以总点数-最大匹配数=有多少个点是结尾节点
所以可得那个更简短的公式:
DAG的最小路径覆盖数=DAG图中的节点数-相应二分图中的最大匹配数.

POJ 2594 DAG最小的可相交路径覆盖

解法:先用floyd若u可以到达v则在二分图上连接u->v。接下来的步骤就和上一题一样了(求最大匹配数)。
翻了很多篇博客都没有对于解法的解释证明。
在这里借用上一题的证明感性理解一下:
最大匹配数也就是看多少个节点不是结尾节点。在这里DAG中一个节点(u)能到达另一节点(v),那二分图上一定有边使它们(u->v)相连。因为没说一个节点只能被一条路径经过,所以u在与v相连后在DAG中就不会受限制了。(限制指:在DAG中u->u’直接相连但u’已匹配别的点因此u和u’不能匹配,因此u变成结尾节点。而这题中新的建二分图方式就可使u与v相匹配,而u就不会变成结尾节点了)。

HDU 1150&&POJ 1325 最小顶点覆盖
POJ 2446

做了这道题但是有个地方还没想通,先不放题解了

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 50;
const int NN = 2024 + 10;
const int M = 200000 + 10;
int n,m,k;
int a[N][N],head[NN],to[M],nxt[M],etot;
bool vis[NN];int match[NN];
int p(int i,int j){
    return (i-1)*n+j;
}
void adde(int u,int v)
{
    to[++etot]=v;
    nxt[etot]=head[u];
    head[u]=etot;
}
bool hungary(int u)
{
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(vis[v]) continue;
        vis[v]=1;
        if(!match[v]||hungary(match[v])){
            match[v]=u;return 1;
        } 
    }
    return 0;
}
void init()
{
    etot=0;
    memset(head,0,sizeof(head));
    memset(a,0,sizeof(a));
    memset(match,0,sizeof(match));
}
int main()
{
    while(scanf("%d%d%d",&m,&n,&k)!=EOF){
        init();
        for(int i=1;i<=k;i++){
            int x,y;
            scanf("%d%d",&x,&y);//[y][x]
            a[y][x]=1;
        }
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        if(!a[i][j]){
            if(!a[i-1][j]&&i-1>=1){
                if((i+j)%2) adde(p(i,j),p(i-1,j));
                else adde(p(i-1,j),p(i,j));
            }
            if(!a[i][j-1]&&j-1>=1){
                if((i+j)%2) adde(p(i,j),p(i,j-1));
                else adde(p(i,j-1),p(i,j));
            }
        }
        int mch=0;
        for(int i=1;i<=n*m;i++)
        if(head[i]){
            memset(vis,0,sizeof(vis));
            if(hungary(i)) mch++;
        } 
        if(mch*2==n*m-k) printf("YES");
        else printf("NO");
    }

    return 0;
}
HDU 2819

http://www.cnblogs.com/gj-Acit/archive/2013/08/17/3265502.html
感觉这篇证明构建二分图的超清晰!!
不过性质的证明我看了那么多题解还是没有懂……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值