HDU - 2444——The Accomodation of Students(判断二分图,二分图最大匹配)

本文探讨了如何通过判断无向图是否为二分图并使用匈牙利算法求解最大匹配的问题,详细介绍了二分图的概念、判断方法及最大匹配的实现过程。

题意:

题意: 有n个人,m对人相互认识; 问能否分成两个组,组内任意两个人之间不认识; 若不能,则输出No; 若能,则相互认识的两个人一间房,求最多需要几间房;
给出一些学生的认识情况,比如A和B认识,B和C认识,但是A和C不一定认识。现在问能否将这些学生分成两个组,并且每组中的学生互相不认识,如果能分,求出最大能匹配的学生对数。

题目

There are a group of students. Some of them may know each other, while others don’t. For example, A and B know each other, B and C know each other. But this may not imply that A and C know each other.

Now you are given all pairs of students who know each other. Your task is to divide the students into two groups so that any two students in the same group don’t know each other.If this goal can be achieved, then arrange them into double rooms. Remember, only paris appearing in the previous given set can live in the same room, which means only known students can live in the same room.

Calculate the maximum number of pairs that can be arranged into these double rooms.

Input

For each data set:
The first line gives two integers, n and m(1<n<=200), indicating there are n students and m pairs of students who know each other. The next m lines give such pairs.

Proceed to the end of file.

Output

If these students cannot be divided into two groups, print “No”. Otherwise, print the maximum number of pairs that can be arranged in those rooms.

Sample Input

4 4
1 2
1 3
1 4
2 3
6 5
1 2
1 3
1 4
2 5
3 6

Sample Output

No
3

题解:

1首先bfs判断是否是二分图,然后求二分最大匹配。
2判断是否为二分图:在无向图G中,无向图G为二分图的充分必要条件是:G至少有两个顶点,且当存在回路时,其所有回路的长度均为偶数。回路就是环路,也就是判断是否存在奇数环。如果存在奇数回路(回路中节点个数为奇数),则不是二分图。否则是二分图。
采用染色法+bfs(染色法是将一个点先染色,然后把和它相邻的点染成不同的颜色,如果遇到相邻点的颜色相同的情况就不是二分图
3 染色法判断回路奇偶性:把相邻两点染成黑白两色,如果相邻两点出现颜色相同则存在奇数回路。也就是非二分图。
4匹配的对数:由于是两个相同的集合进行配对,所以最后将结果除2

AC代码

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
const int M=2e2+10;
int n,m,dp[M],book[M],e[M],map[M][M];
bool dfs()//先要判断能否分成两组,使得每组内的人互不认识,即判断是否为二分图
{
    memset(dp,-1,sizeof(dp));//染色数组,-1为未染,0,1则为两种不同颜色
    for(int i=1; i<=n; i++)
    {
        if(dp[i]!=-1)
            continue;
        dp[i]=0;
        queue<int>q;
        q.push(i);
        while(!q.empty())
        {
            int head=q.front();
            q.pop();
            for(int j=1; j<=n; j++)
            {
                if(!map[head][j])
                    continue;
                if(dp[j]!=-1&&dp[head]==dp[j])//把相邻两点染成黑白两色,如果相邻两点出现颜色相同则存在奇数回路。也就是非二分图。
                    return false;
                else if(dp[j]==-1)
                {
                    dp[j]=!dp[head];
                    q.push(j);
                }
            }
        }
    }
    return true;
}
bool math(int x)//匈牙利算法
{
    for(int i=1; i<=n; i++)
        if(!book[i]&&map[x][i])
        {
            book[i]=1;
            if(!e[i]||math(e[i]))
            {
                e[i]=x;
                return true;
            }
        }
    return false;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(map,0,sizeof(map));
        for(int i=1; i<=m; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            map[a][b]=map[b][a]=1;
        }
        if(dfs()==false)
        {
            printf("No\n");
            continue;
        }
        int ans=0;
        memset(e,0,sizeof(e));
        for(int i=1; i<=n; i++)
        {
            memset(book,0,sizeof(book));
            if(math(i))
                ans++;
        }
        printf("%d\n",ans/2);//求对数,除2
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值