题目描述:
Bobo has a graph with n vertices and m edges where the i-th edge is between the vertices ai and bi. Find out whether is possible for him to choose some of the edges such that the i-th vertex is incident with exactly di edges.
输入:
2 1
1 1
1 2
2 1
2 2
1 2
3 2
1 1 2
1 3
2 3
输出:
Yes
No
Yes
题目大意:
给你m条边,n个点,要从m条边中选择一部分,和n个点构成一张图,是否能在满足每个点正好连有d[i]条边的情况下完成,能完成输出Yes,不能输出No
??直接统计加入所有边后的入度出度,看看是不是比d[i]大不就行了?
还真不行。度是针对于点去统计的,这个题则是去选择一些边,比如下图:
假如,d[1]=2,d[2]=d[3]=d[4]=1,d[i]确实小于i的度但却是不成立的,所以不能单纯地去看度的大小,还要看匹配的情况:
窝的想法是,第i个点的每一个度都要跟相应的边去匹配,那么,不妨把边化成点,然后边和与其相连的点去连线,如下图:
可是这样做还是看不出明显的两两匹配,我们就想到,一条边是去连接两个点,因此匹配的时候需要两侧都匹配,所以对于每一条边应该去建两个虚点才行,如图:
哎?你看这个两两匹配就很明显了,比如说(1-2)那条边,建立了5和6两个虚点,5和1匹配,6和2匹配,那么说明这条边被加入图中了,再比如说(1-3)那条边,建立了7和8两个虚点,而7和8自身匹配了起来就说明这条边不会加入最后的图中
但是对上面的方法来讲都是在d[i]=1的情况下,d[i]大于1的时候,一个点已经不够了,所以我们需要对于第i个点,每有一个d[i]就多建立一个虚点,对于每一条边,如果这条边和第j个点相连,则需把那一侧的虚点和第j个点的所有虚点都相连,如图:
如图,图中出现了一个没有被匹配上的点,所以答案是NO,再比如:
这组数据达到了完全匹配,所以是可以的。那么建图方法我就说完了,但是匹配······因为不是二分图,也就是说图中在增广路径的时候会出现奇环,所以需要另一种算法:带花树算法,用于普通图中的最大匹配。
带花树在下面这篇博客里可以找到:
接下来直接上代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define rt int
using namespace std;
inline rt read()
{
register char ch=getchar();register rt u=0,v=0;
while(!isdigit(ch)){
if(ch=='-')v=1;ch=getchar();}
while(isdigit(ch)){
u=u*10+ch-'0';ch=getchar();}
return v?-u:u;
}
const rt maxn=505;
const rt maxm=maxn*maxn*2;
rt d[maxn],node[maxn][3],x,y;
rt n,m,que[maxm