二分图匹配&&最大团&&最大独立集&&完全图运用

Kindergarten POJ - 3692 

                                               可以不看定义直接往下拉

最大团的定义:

设一个无向图G(V,E) ,V 为点集,E 为两点间的边集。设U 为V 的一个子集,若对于任意的结点对u ,v 属于U 都有边连通,则称点集U构成的图为 完全子图 。无向图G 的完全子图U 是G 的团,G 的最大团即为G 的最大完全子图
 

最大团与最大独立集的关系:
求解一个图中的最大独立集等价于求解其补图的最大团。
独立集的条件是任意两个点互不连通,那么如果把原图中连通的点之间的边删除,不连通点连接,即转化为求个数最多的两两连通点集,也即求最大团。

二分图的最大独立集

二分图的最大独立集=点数-最小顶点覆盖

证明:

最小顶点覆盖是图G中任意边都有至少一个端点属于S的顶点集合(S为顶点覆盖集合),那么将这些被覆盖的边删完,剩下的不就是没有关系即没有连通了点了吗

我们可以这样想,先把所有的点放进集合,然后删去最少的点和与之相关联的边,使得全部边都被删完,这就是最小点覆盖。所以有:最大独立集=点数-最小点覆盖

/*---------------------------------------------------------------------------------------------------------*/

题意:一群男孩子和女孩子,男孩子之间相互了解,女孩子之间也相互了解,有一些男孩子和女孩子之间也相互了解,现在要搞一个活动,要你选出一群人,这个人之间都要相互了解,问你这群人的最大数目是多少。 

由题意知:这男生和女生两个集合是两个完全图顶点两两之间有且只有一条边连接,即每对不同的顶点之间都恰连有一条边相连

那么我们现在稍微整理一下上面的定义(不用回去看)

最大完全数:最大完全子图中顶点的个数

独立集:图中任意两点都不相连的顶点集合

完全子图:任意两点都相连的顶点集合

本题求的是两两之间存在联系的最大集合,即图中最大完全子图的顶点个数。二分图中的左右集合是没有内部边的,但是本题的图不符合二分图的定义,所以我们将之转化为二分图求解,即将原本的图转过来,将原本有联系的两个点拆开,将原本没有联系的连接,那么求此新图的最大独立集,独立集是两两互无关系,那么推回原图就是两两互有联系了。。。十分巧妙的一个题目

用更严格一点的说法就是两个完全子图组成原图,其补图一定是二分图。二分图的最大独立集即为所求,因为独立集两两之间没有边,代表原图两两彼此有关系。----- POJ 3692 Kindergarten​ 题解 《挑战程序设计竞赛》-码农场  

这是我之前不理解的地方,为什么说其补图一定是二分图,你想,两个完全子图内部两两恰有一边相连,两图之间用任意边连接(可以暂时忽略)组成一张新图,其补图就是原本相连的点,拆开,原本不相连的点连接,两个子图A,B即两个点集内部两两互不连接,符合二分图的性质,易证补图的每条边所关联的两个顶点分别属于点集A,B

#include<iostream>
#include<cstring>
#include<math.h>
#include<stdlib.h>
#include<cstring>
#include<cstdio>
#include<utility>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn=1e3+10;
int girl[maxn],head[maxn],vis[maxn][maxn],used[maxn];
int n,m,s,t,k,g,b;
const int inf=0x3f3f3f3f;
int maxflow=0;
int cnt;//这个地方要注意一下反向边的异或,如果从下标1开始,那么他的反向边是0 
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(!used[now]){
			
			used[now]=1;//标志该男生在此次查找中已被询问 
			
			if(!girl[now]||Find(girl[now])){//腾位置,撬墙脚 
				girl[now]=idx;//符合条件则将该女生和该男生匹配上,并标记 
				return 1;
			}
			
		} 
	}
	return 0;
}
int main()
{	
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	
	//最大独立团问题 
	int step=1;
	while(cin>>g>>b>>k){
		
		if(g==0&&b==0&&k==0)break;
		cnt=0;
		memset(head,-1,sizeof(head));
		memset(girl,0,sizeof(girl));
		memset(vis,0,sizeof(vis));
		
		int x,y;
		
		for(int i=1;i<=k;++i){
			
			cin>>x>>y;
			
			vis[x][y]=1;
			
			//add(x,y);
		}
		
		for(int i=1;i<=g;++i){
			for(int j=1;j<=b;++j)
			if(!vis[i][j])add(i,j);
		}
		
		//x=read();
		ll ans=0;
		for(int i=1;i<=g;++i){
			
			memset(used,0,sizeof(used));
			
			if(Find(i))ans++;
			
		}
	   	cout<<"Case "<<step++<<": "<<g+b-ans<<endl;
	}
    
    
    
    return 0;
}

附:

 POJ3692_FlushHip的博客-CSDN博客

https://blog.csdn.net/qq_41730082/article/details/81456611 图论——最大团问题和最大独立集、二分图相关_上总介的博客-CSDN博客_最大团和最大独立集   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值