poj1469 二分图最大匹配 匈牙利算法BFS实现

                                                         POJ 1469

二分图讲解:点击打开链接

大致题意:

有n个学生和p门课程,每个人可以选0,1,2......门课程。给你每个学生喜欢的课程编号,然后问你是否能从n中选p个学生,使得每个学生所选的课程都不同且每门课程都有一个人选。

大致思路:

其实题意就是问你是否能找出p个1对1的关系。那么根据二分图最大匹配性质,我们只需找出最大匹配数,看是否和课程书相同,是的话,那就代表能成功。

直接套模板,我用的是BFS,据说BFS比DFS更稳定。

代码:

#include<stdio.h>
#include<iostream>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;
int pre[305],vis[305];pre数组用来存储路径,等更改匹配边时要用到。
int ml[305],mr[305];//左集合点的匹配点  右集合点的匹配点   
int p,n;
vector<int>V[30005];//vector存图
int MaxMatch()//bfs实现匈牙利算法
{
    int ans=0;
    memset(vis,0,sizeof(vis));
    memset(ml,-1,sizeof(ml));
    memset(mr,-1,sizeof(mr));
    for(int i=1; i<=p; i++)
    {
        if(ml[i]!=-1)continue;
        queue<int>Q;
        Q.push(i);
        pre[i]=-1;
        int flag=0;//是否找到增广路
        while(!Q.empty()&&!flag)
        {
            int v=Q.front();
            Q.pop();
            for(int j=0; j<V[v].size()&&!flag; j++)
            {
                int to=V[v][j];
                if(vis[to]!=i)
                {
                    vis[to]=i;
                    Q.push(mr[to]);
                    if(mr[to]>=0)
                    {
                        pre[mr[to]]=v;//没找到增广路,记下路径
                    }
                    else//找到了
                    {
                        flag=1;
                        int d=v;
                        int e=to;
                        while(d!=-1)//更改路径
                        {
                            int temp=ml[d];
                            ml[d]=e;
                            mr[e]=d;
                            e=temp;
                            d=pre[d];
                        }
                    }
                }
            }
        }
        if(flag)ans++;//找到增广路,匹配边加一条

    }
    return ans;

}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {

        scanf("%d%d",&p,&n);
        int num,a;
        for(int i=1; i<=p; i++)
        {
            V[i].clear();
            scanf("%d",&num);
            for(int j=1; j<=num; j++)
            {
                scanf("%d",&a);
                V[i].push_back(a);
            }
        }
        int ans=MaxMatch();
        //printf("%d\n",ans);
        if(ans==p)
            printf("YES\n");
        else
            printf("NO\n");

    }
}

第一次做二分图类题,看了一下午,终于略有所懂,写一道简单题找找感觉~~~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值