二分图总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41661919/article/details/86378280

<一>

一、什么是二分图:

      算法竞赛中定义:首先是一张N个点的无向图,其次这N个点可以分成A、B两个部分,A交B为空集,且同一集合中的点没有边相连(不同集合中的两个点之间可能有边相连也可能没有边相连,可能一条也可能多条)。

      离散中定义(对偶图):任取一条边,该边的两个端点一定处于两个不同的集合中。

二、判断某一无向图是不是二分图。

1、原理:二分图中所有回路的路径长度均为偶数,即不存在长度为奇数的回路。

2、思路:黑白点标记判断标记是否会出现矛盾。

3、实现代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include<algorithm>
#include <set>
#include <queue>
#include <stack>
#include<vector>
#include<map>
#include<ctime>
#define ll long long
using namespace std;
const int N=10010;
const int M=10010*4;
int Next[M];
int ver[M];
int head[N];
int tot;
void add(int x,int y)
{
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
int color[N];
bool dfs(int x,int c)
{
    color[x]=c;
    for(int i=head[x];i;i=Next[i])
    {
        int y=ver[i];
        if(color[y]==c)return 0;
        if(!color[y]&&dfs(y,-c)==false)return 0;//不用担心往回跑的情况

    }
    return 1;
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        memset(head,0,sizeof(head));
        memset(ver,0,sizeof(ver));
        memset(Next,0,sizeof(Next));

        tot=0;
        memset(color,0,sizeof(color));
        for(int i=1;i<=m;++i)
        {
            int x,y;
            cin>>x>>y;
            add(x,y);
            add(y,x);
        }

        int ans=1;
        for(int i=1;i<=n;++i)
        {
            if(color[i]==0&&!dfs(i,1))
            {
                ans=0;
                break;
            }

        }
        cout<<ans<<endl;


    }
    return 0;
}

4、例题:codevs1069 关押罪犯 http://codevs.cn/problem/1069/

题解:https://blog.csdn.net/qq_41661919/article/details/86422452

<二>二分图最大匹配(边数最多的一组匹配)

一、增广路概念及性质:

1、长度一定为奇数;

2、奇数边为非匹配边,偶数号边为匹配边;

3、原图中匹配状态取反后的图仍为匹配图,且最大匹配数+1;

二、匈牙利算法求最大匹配值:

1、原理:不断寻找增广路,匹配数相应+1,详细较复杂,可以再看看书,或者博客。

个人理解的话就是看每个左部节点能不能找到它的匹配节点,通过增广路算法得到的已经匹配的点不会变为非匹配节点,顶多更换匹配对象。能找到匹配数+1,找不到不变。

https://blog.csdn.net/dark_scope/article/details/8880547

https://blog.csdn.net/qq_38956769/article/details/80238896

2、算法代码实现:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include<algorithm>
#include <set>
#include <queue>
#include <stack>
#include<vector>
#include<map>
#include<ctime>
#define ll long long
using namespace std;
const int N=20010;
const int M=100001*2;
int Next[M];
int ver[M];
int head[N];
int tot;
void add(int x,int y)
{
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
bool visit[N];
int match[N];
bool dfs(int x)
{
    for(int i=head[x];i;i=Next[i])
    {
        int y=ver[i];
        if(!visit[y])
        {
            visit[y]=1;
            if(!match[y]||dfs(match[y]))//对立点没有被使用,或者占用它的左节点可以
            {
                match[y]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        memset(head,0,sizeof(head));
        memset(Next,0,sizeof(Next));
        memset(ver,0,sizeof(ver));
        tot=0;
        memset(match,0,sizeof(match));
        for(int i=1;i<=m;++i)
        {
            int x,y;
            cin>>x>>y;
            add(x,y);
            add(y,x);
        }
        int ans=0;
        for(int i=1;i<=n;++i)//遍历每一个左部节点(不好确定谁是左部节点的时候可以遍历所有节点,然后ans/2),看能不能找到其在右边的对应匹配节点
        {
            memset(visit,0,sizeof(visit));//visit只是一个临时标记,只在单一节点为起点的搜索中起作用,搜一个节点更新一次;
            if(dfs(i))ans++;
        }
        cout<<ans/2<<endl;
    }
    return 0;
}

3、

例题1:TYVJ棋盘覆盖  

题解:https://blog.csdn.net/qq_41661919/article/details/86429537

例题2:車的放置 蓝书

题意:N*M的棋盘,某些个子进制放置棋子,问棋盘上最多能防止多少个不能相互攻击的車。N,M<=200。

分析:

      1要素:1行只能有一个棋子,一列同样只能有一个棋子。棋子可以同时占某一行和某一列。

      0要素:不同行或者不同列之间不会同时有同一个棋子。

      最终,所以左部节点为行号,右部节点为列号,连线表示棋子,建立二分图。

三、完备匹配概念。

     二分图左右部节点数相同,且二分图最大匹配数==n。

四、二分图最小点覆盖。

1、定义:二分图中一最小点集S,使得从二分图中任取一条边,该边至少以一个端点位于S中。即能够覆盖所有边的最小S集。

2、定理:二分图最小覆盖点包含的点数等于二分图最大匹配包含的边数。

例题:POJ 1325 Machine Schedule

题解:https://blog.csdn.net/qq_41661919/article/details/86444389

五、二分图最大独立集:

1、定义:任意两点之间没有边相连的最大点集。最大团:任意两点之间均有边相连的最大点集。

2、定理:二分图的最大独立集中点的个数等于n(左+右)-二分图的最大匹配。

      定理:二分图的最大团中点的个数等于二分图补图的最大匹配。

六、有向无环图的最小不相交路径点覆盖:

七、有向无环图的最小可相交路径点覆盖:

猜你喜欢

转载自blog.csdn.net/qq_41661919/article/details/86378280
今日推荐