二分图的判断和二分图最大匹配模板

二分图的判定:是否能够将点集分成两个集合,使得对于每条边都有该边的一个点在一个集合,另一个在另一个集合。


hihocoder 1121  二分图判定

题目链接:hihocoder 1121


们的问题就转化为判定是否存在一个合理的染色方案,使得我们所建立的无向图满足每一条边两端的顶点颜色都不相同

那么,我们不妨将所有的点初始为未染色的状态。随机选择一个点,将其染成白色。再以它为起点,将所有相邻的点染成黑色。再以这些黑色的点为起点,将所有与其相邻未染色的点染成白色。不断重复直到整个图都染色完成。(如下图)

在染色的过程中,我们应该怎样发现错误的记录呢?相信你一定发现了吧。对于一个已经染色的点,如果存在一个与它相邻的已染色点和它的颜色相同,那么就一定存在一条错误的记录。(如上图的4,5节点)

到此我们就得到了整个图的算法:

  1. 选取一个未染色的点u进行染色
  2. 遍历u的相邻节点v:若v未染色,则染色成与u不同的颜色,并对v重复第2步;若v已经染色,如果 u和v颜色相同,判定不可行退出遍历。
  3. 若所有节点均已染色,则判定可行。

分析:按照提示写出判断

#include<cstdio>
#include<vector>
#include<map>
#include<queue>
#include<string.h>
#include<iostream>
#include<cmath>
#include<algorithm>

using namespace std;

int vis[10005];
vector<int> vt[10005];
queue<int> qt;
int n,flag,t;

int main()
{
	int cas,i,m,a,b;
	scanf("%d",&cas);
	while(cas--)
	{
		scanf("%d %d",&n,&m);
		
		for(i=0;i<=n;i++) 
			vt[i].clear();
		while(!qt.empty()) qt.pop();

		for(i=0;i<m;i++)
		{
			scanf("%d %d",&a,&b);
			vt[a].push_back(b);
		}
		if(n==1) 
		{ 
			printf("Correct\n"); 
			continue;
		}
		memset(vis,0,sizeof(vis));
		vis[a]=1;
		flag=0;
		for(i=0;i<vt[a].size();i++)
		{
			vis[vt[a][i]]=2;
			qt.push(vt[a][i]);
		}
		while(!qt.empty())
		{
			t=qt.front(); qt.pop();
			for(i=0;i<vt[t].size();i++)
			{
				int tt=vt[t][i];
				if( vis[tt]==0) 
				{
					if(vis[t]==1) vis[tt]=2;
					else vis[tt]=1;
					qt.push(tt);
				}
				else if( vis[tt]==vis[t]) { flag=1; break; }
			}
		}
		if(flag==1) 
			puts("Wrong");
		else 
			puts("Correct");
	}
}

二分图最大匹配的模板:
DFS实现:(邻接表 用vector数组实现
const int maxn=512;
bool used[maxn];
vector<int>g[maxn];
int L,R;
int x[maxn],y[maxn];
bool SearchPath(int u)
{
	int Size=g[u].size(),v;
     for(int i=0;i<Size;i++)
	 {
		 v=g[u][i];
	   if(!used[v])
	   {
	    used[v] = true;
		if(y[v] == -1 || SearchPath(y[v]))
		{
		  y[v]=u;
		  x[u]=v;
		  return true;
		}
	   }
	 }
	 return false;
}
int MaxMatch()
{
	 int ret=0;
	 memset(x,-1,sizeof(x));
	 memset(y,-1,sizeof(y));
	 for(int u=1;u<=L;u++)
	 {
		if(x[u]==-1)
		{
		   memset(used,false,sizeof(used));
			if(SearchPath(u))
			   ret++;
		}
	 }
	 return ret;
}

BFS实现:( 邻接矩阵 用二维数组实现
const int maxn=512;
int g[maxn][maxn];
int L,R;
int x[maxn],y[maxn];

int Q[maxn]; //模拟队列
int pre[maxn];
int MaxMatch()
{
    int res=0,temp;
	memset(x,-1,sizeof(x));
	memset(y,-1,sizeof(y));
	for(int i=1;i<=L;i++)
	{
		if(x[i]==-1)
		{
			int cur=0,tail=0;
			for(int j=1;j<=R;j++)
			{
				if(g[i][j])
					pre[j]=-1,Q[tail++]=j;
				else 
					pre[j]=-2;
			}

			//BFS
			while(cur<tail)
			{
				temp=Q[cur];
				if(y[temp]==-1)
					break;
				cur++;
				for(int j=1;j<=R;j++)
				{
					if(pre[j]==-2&&g[y[temp]][j])
					{
						pre[j]=temp;
						Q[tail++]=j;
					}
				}
			}
			//end of BFS

			if(cur==tail)  //没有找到交错轨
				continue;
			while(pre[temp]>-1)  //更改交错轨上匹配状态
			{
				x[ y[pre[temp]] ]=temp;
				y[temp]=y[pre[temp]];
				temp=pre[temp];
			}
			y[temp]=i;x[i]=temp;
			res++;
		}
	}
	return res;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值