860. 染色法判定二分图
给定一个 n
个点 m
条边的无向图,图中可能存在重边和自环。
请你判断这个图是否是二分图。
输入格式
第一行包含两个整数 n
和 m
。
接下来 m
行,每行包含两个整数 u 和 v,表示点 u 和点 v
之间存在一条边。
输出格式
如果给定图是二分图,则输出 Yes
,否则输出 No
。
数据范围
1≤n,m≤105
输入样例:
4 4
1 3
1 4
2 3
2 4
输出样例:
Yes
* 先将任意一个顶点染成一种颜色,再将相邻顶点染成另一种颜色,重复每一个顶点(对于
* 接下来还没有染色的点(此点一定和之前染过色的顶点不是连通的),任意染成一种颜色,
* 将相邻的顶点染成另外一种颜色,);如果对于每个顶点其相邻顶点的颜色都不相同,
* 那么说明此图是二分图;
/**
* 先将任意一个顶点染成一种颜色,再将相邻顶点染成另一种颜色,重复每一个顶点(对于
* 接下来还没有染色的点(此点一定和之前染过色的顶点不是连通的),任意染成一种颜色,
* 将相邻的顶点染成另外一种颜色,);如果对于每个顶点其相邻顶点的颜色都不相同,
* 那么说明此图是二分图;
*/
#include
#include
#include
using namespace std;
const int maxn = 1e5+10;
vector Adj[maxn];
int color[maxn]; //每个顶点是否着色
int Nv,Ne; //顶点数,边数
void Read() //读入数据
{
cin >> Nv >> Ne;
for(int i=0;i> u >> v;
Adj[u].push_back(v);
Adj[v].push_back(u);
}
}
int dfs(int u,int c) //对u这个顶点进行着色
{
color[u]=c;
for(int i=0;i
861. 二分图的最大匹配
给定一个二分图,其中左半部包含 n1
个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m
条边。
数据保证任意一条边的两个端点都不可能在同一部分中。
请你求出二分图的最大匹配数。
二分图的匹配:给定一个二分图 G
,在 G 的一个子图 M 中,M 的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M
是一个匹配。
二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。
输入格式
第一行包含三个整数 n1
、 n2 和 m
。
接下来 m
行,每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v
之间存在一条边。
输出格式
输出一个整数,表示二分图的最大匹配数。
数据范围
1≤n1,n2≤500
,
1≤u≤n1,
1≤v≤n2,
1≤m≤105
输入样例:
2 2 4
1 1
1 2
2 1
2 2
输出样例:
2
* 虽然题目说每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v
* 之间存在一条边。看着是无向边,但是处理起来,只能看作是单向边,因为是左部和右部
* 相连,左部存在n1个顶点( 1,2,……,n1),右部存在n2个顶点(1,2,……,n2);
* 处理成无向图,就不存在左部和右部之分,与题意不符合要求;
/**
* 对于还没有匹配到“对象”的顶点v,这简单,直接让u和v匹配在一起就完事儿了;
* 或者已经匹配到对象的顶点v,但是想给v换一个“对象”,这就有点麻烦了,得问问
* v的对象match[v],看他是否有其他中意的人,让他去找其他人,如果能找到,那就让
* match[v]和他中意的那个人,而v就从现任变为前任,转而让u和v在一起;
* 如果一直搜索完所有人,都不能使v与match[v]分开,那么注定u与v是有缘无份,不能够
* 在一起;
* 以上就是dfs完成的操作:
*/bool dfs(int u)
{
for(int v=1;v<=n2;++v) //遍历右半部分的顶点
{
if(hs[v]==0 && G[u][v]==1) //v还未被访问
{
hs[v]=1; //记录v未被访问
if(match[v]==0 || dfs(match[v])) //v还未被匹配或者给v换一个对象能够成功
{
match[v]=u; //因为是单向边,不是双向边,这一轮比较完以后,
return 1; //下一轮左边并不会用到u这个数;
}
}
}
return 0;
}
int max_bin_graph()
{
int sum=0;
for(int i=1;i<=n1;++i)
{
fill(hs,hs+maxn,0); //清除上一轮的标记
if(dfs(i)==1)
++sum;
}
return sum;
}
/**
* 虽然题目说每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v
* 之间存在一条边。看着是无向边,但是处理起来,只能看作是单向边,因为是左部和右部
* 相连,左部存在n1个顶点( 1,2,……,n1),右部存在n2个顶点(1,2,……,n2);
* 处理成无向图,就不存在左部和右部之分,与题意不符合要求;
*/
#include
#include
#include
using namespace std;
const int maxn = 510;
int G[maxn][maxn]; //邻接矩阵
int match[maxn]; //边匹配
int hs[maxn]; //顶点是否被访问
int n1,n2,m;
void Read()
{
cin >> n1 >> n2 >> m;
for(int i=0;i> u >> v;
G[u][v]=1;
}
}
/**
* 对于还没有匹配到“对象”的顶点v,这简单,直接让u和v匹配在一起就完事儿了;
* 或者已经匹配到对象的顶点v,但是想给v换一个“对象”,这就有点麻烦了,得问问
* v的对象match[v],看他是否有其他中意的人,让他去找其他人,如果能找到,那就让
* match[v]和他中意的那个人,而v就从现任变为前任,转而让u和v在一起;
* 如果一直搜索完所有人,都不能使v与match[v]分开,那么注定u与v是有缘无份,不能够
* 在一起;
* 以上就是dfs完成的操作:
*/
bool dfs(int u)
{
for(int v=1;v<=n2;++v) //遍历右半部分的顶点
{
if(hs[v]==0 && G[u][v]==1) //v还未被访问
{
hs[v]=1; //记录v未被访问
if(match[v]==0 || dfs(match[v])) //v还未被匹配或者给v换一个对象能够成功
{
match[v]=u; //因为是单向边,不是双向边,这一轮比较完以后,
return 1; //下一轮左边并不会用到u这个数;
}
}
}
return 0;
}
int max_bin_graph()
{
int sum=0;
for(int i=1;i<=n1;++i)
{
fill(hs,hs+maxn,0); //清除上一轮的标记
if(dfs(i)==1)
++sum;
}
return sum;
}
int main()
{
Read();
cout << max_bin_graph() << endl;
return 0;
}
再增加一题:
12095. 4.2-2完美的牛栏
提高+/省选-
题目详情
题解
测评详情
农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术。不幸的是,由于工程问题,每个牛栏都不一样。第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在她们喜欢的那些牛栏中产奶。上个星期,农夫约翰刚刚收集到了奶牛们的爱好的信息(每头奶牛喜欢在哪些牛栏产奶)。一个牛栏只能容纳一头奶牛,当然,一头奶牛只能在一个牛栏中产奶。
给出奶牛们的爱好的信息,计算最大分配方案。
输入格式:
第一行 两个整数,N (0 <= N <= 200) 和 M (0 <= M <= 200) 。N 是农夫约翰的奶牛数量,M 是新牛棚的牛栏数量。 第二行到第N+1行 一共 N 行,每行对应一只奶牛。第一个数字 (Si) 是这头奶牛愿意在其中产奶的牛栏的数目 (0 <= Si <= M)。后面的 Si 个数表示这些牛栏的编号。牛栏的编号限定在区间 (1..M) 中,在同一行,一个牛栏不会被列出两次。
输出格式:
只有一行。输出一个整数,表示最多能分配到的牛栏的数量。
样例 1 :
输入: 5 5 2 2 5 3 2 3 4 2 1 5 3 1 2 5 1 2
输出: 4
照猫画虎:二分图的最大匹配
#include
#include
using namespace std;
const int maxn = 210;
int G[maxn][maxn];
int match[maxn];
bool hs[maxn];
int n,m;
void Read()
{
cin >> n >> m;
for(int i=1;i<=n;++i)
{
int cnt;
cin >> cnt;
for(int j=0;j>x;
G[i][x]=1;
}
}
}
bool dfs(int u)
{
for(int v=1;v<=m;++v)
if(hs[v]==0 && G[u][v]==1)
{
hs[v]=1;
if(match[v]==0 || dfs(match[v]))
{
match[v]=u;
return 1;
}
}
return 0;
}
int max_bin_graph()
{
int sum=0;
for(int i=1;i<=n;++i)
{
fill(hs,hs+maxn,0);
if(dfs(i))
++sum;
}
return sum;
}
int main()
{
Read();
cout << max_bin_graph() << endl;
return 0;
}