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");
}
}
第一次做二分图类题,看了一下午,终于略有所懂,写一道简单题找找感觉~~~~~