二分图-染色法&匈牙利算法

染色法判定二分图

算法思路

二分图:就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。

如何判定是否为二分图:当且仅当图中不含有奇数环

代码思路:
    染色可以使用1和2区分不同颜色,用0表示未染色
    遍历所有点,每次将未染色的点进行dfs, 默认染成1或者2
    由于某个点染色成功不代表整个图就是二分图,因此只有某个点染色失败才能立刻break/return
    染色失败相当于至少存在2个点染了相同的颜色

代码

题目:https://www.acwing.com/problem/content/description/862/

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=2e5+10;

int n,m;
int h[N],ne[M],e[M],idx;
int color[N];

//邻接表加边
void add(int u,int v)
{
    e[idx]=v;
    ne[idx]=h[u];
    h[u]=idx++;
}
//深度优先遍历
bool dfs(int k,int v)
{
    int i,j;
    //标记数组
    color[k]=v;
    //邻接表遍历
    for(i=h[k];i!=-1;i=ne[i])
    {
        j=e[i];
        if(!color[j])
        {
            if(!dfs(j,3-v))
                return false;
        }
        //若相邻,判断染得色是否一样
        else if(color[j]==v)
            return false;
    }
    return true;
}

int main()
{
    int i,j;
    cin>>n>>m;
    //初始化h数组为-1
    memset(h,-1,sizeof(h));
    while(m--)
    {
        int u,v;
        cin>>u>>v;
        //无向图
        add(u,v);
        add(v,u);
    }
    bool flag=false;
    for(i=1;i<=n;i++)
    {
        if(!color[i])
        {
            if(!dfs(i,1))
            {
                flag=true;
                break;
            }
        }
    }
    if(flag)
        cout<<"No";
    else
        cout<<"Yes";
    return 0;
}

匈牙利算法

算法思路

要了解匈牙利算法必须先理解下面的概念:

匹配:在图论中,一个「匹配」是一个边的集合,其中任意两条边都没有公共顶点。

最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。

算法描述:
如果你想找的妹子已经有了男朋友,
你就去问问她男朋友,
你有没有备胎,
把这个让给我好吧

多么真实而实用的算法

具体实现:

用到递归,判断新加入的会不会是匹配的数目增多。

TIP: 因为你要去问的都是男孩子,所以存边的时候,都是由男孩子指向女孩子

代码

题目:https://www.acwing.com/problem/content/863/

#include<bits/stdc++.h>
using namespace std;
const int N=550,M=1e5+10;
int n1,n2,m;
int h[N],e[M],ne[M],idx;
//st[]数组我称为临时预定数组,st[j]=a表示一轮模拟匹配中,女孩j被男孩a预定了。
bool st[N];
//match[j]=a,表示女孩j的现有配对男友是a
int match[N];

void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
//这个函数的作用是用来判断,如果加入x来参与模拟配对,会不会使匹配数增多
bool find(int x)
{
    int i,j;
    //遍历自己喜欢的女孩
    for(i=h[x];i!=-1;i=ne[i])
    {
        j=e[i];
        if(!st[j])//如果在这一轮模拟匹配中,这个女孩尚未被预定
        {
            st[j]=true;//那x就预定这个女孩了
            //如果女孩j没有男朋友,或者她原来的男朋友能够预定其它喜欢的女孩。配对成功,更新match
            if(match[j]==0||find(match[j]))
            {
                match[j]=x;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    int i,j;
    memset(h,-1,sizeof(h));
    cin>>n1>>n2>>m;
    while(m--)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
    }
    int ans=0;
    for(i=1;i<=n1;i++)
    {
        //因为每次模拟匹配的预定情况都是不一样的所以每轮模拟都要初始化
        memset(st,false,sizeof(st));
        if(find(i))
            ans++;
    }
    cout<<ans;
    return 0;
}

衷心提示:宁错误,莫错过

posted @ 2021-02-05 14:53  清风紫雪  阅读(141)  评论(0编辑  收藏  举报