上大佬博客
https://blog.csdn.net/acdreamers/article/details/8621130
https://blog.csdn.net/qq_41730082/article/details/81456611
https://blog.csdn.net/qq_34921856/article/details/79535004
https://blog.csdn.net/Flynn_curry/article/details/52966283
(1)最小顶点覆盖
最小顶点覆盖要求用最少的点,让每条边都至少和其中一个点关联。即点集里面的点能覆盖所有的边
Knoig定理:二分图的最小顶点覆盖数=二分图的最大匹配数。
算法证明:(真特么难懂)
理解①:首先,最小顶点覆盖一定>=最大匹配,因为假设最大匹配为n,那么我们就得到了n条互不相邻的边,光覆盖这些边就要用到n个点。
这里事实上就可以看出最小顶点覆盖和最大匹配的不同了,最大匹配的点一定是两两成对的,而最小顶点覆盖还有相对孤立的点。注意是相对孤立,并不是他们之间肯定没有边,而是不属于匹配范围内的。
那么匹配范围外的节点,一种就是有边和匹配范围内元素相连但是没有匹配到,一种就是没边。
有边的话这个边就连在了匹配范围内,那这个最小顶点覆盖集合就是既可以连接上匹配元素,又可以连接到非匹配元素,相当于这个非匹配范围内的元素被这个集合覆盖
没有边的话就不需要覆盖了啊..因为他没边啊,重新看一眼上面的定义,让每条边都至少和其中一个点关联,既然和边没联系,就不用和他关联了是不是。
至此,匹配范围外的所有节点都不可能影响到最小顶点覆盖数,所以两者完全相等。
理解②:设最小顶点覆盖点集为V
我们先来证明选最大匹配数个点能否把所有的边都覆盖:
当一张二分图达到最大匹配时,左边的点集中未匹配的点肯定不会与右边点集中未匹配的点连接,如果连接,证明含有增广路,可以继续匹配,那么可以得出这么一个结论,达到最大匹配时,左右点集未匹配的点肯定会连接在已匹配的点上
题意:给出n个点的树形图,每一个点可以覆盖与他相连的边,求要覆盖所有边时,最少的顶点数。
思路:树是天然的二分图,看完上面的解析应该就可以做出来了
注意:本题图为双向图,所以结果是最大匹配/2,这种模型一般适用二分图两边的点都一样,否则一般都是建立有向图来匹配的。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=2e3+10;
int girl[maxn],head[maxn],vis[maxn];
int n,m,s,t,k;
const int inf=0x3f3f3f3f;
int maxflow=0;
int cnt;
struct node{
int to,next;
}star[500100];
inline int read(){
int X=0,w=0;char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
void add(int u,int v){
star[cnt].to=v;
star[cnt].next=head[u];
head[u]=cnt++;
}
int Find(int idx){
int now;
for(int i=head[idx];i!=-1;i=star[i].next){
now=star[i].to;//若两人之间有关系且在这次查找中没有被询问
if(!vis[now]){
vis[now]=1;//标志该男生在此次查找中已被询问
if(girl[now]==-1||Find(girl[now])){//腾位置,撬墙脚,//询问是否有伴侣或者可被戴绿帽子
girl[now]=idx;//符合条件则将该女生和该男生匹配上,并标记
return 1;
}
}
}
return 0;
}
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
while(~scanf("%d",&k)){
cnt=0;
memset(head,-1,sizeof(head));
memset(girl,-1,sizeof(girl));//编号从0 开始 所以初始化为-1
//cin>>n>>m;
//scanf("%d %d",&m,&n);
//m=read();n=read();//女生有多个男生
int u,v,w;
for(int i=0;i>x>>y;
//y=read();
}
int ans=0;
for(int i=0;i>1);
////最小顶点覆盖 == 最大匹配(双向图)/2;
//for(int i=0;i