POJ-2446 邻接表+二分图匹配

在孔神的指导下做出了的。。太水了,邻接表都用不好。。。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <algorithm>
#define maxn 1050
using namespace std;
int link[maxn];
bool visit[maxn];
int map[maxn][maxn];
int head[maxn],num;
struct bb
{
	int e,next;
}ed[maxn*8];
void add(int s,int e)//邻接表 
{
	ed[num].e=e;
	ed[num].next=head[s];
	head[s]=num++;
}
bool dfs(int k)//寻找增广路 
{
	for(int i=head[k];i!=-1;i=ed[i].next)
	{
		int e=ed[i].e;
		if(!visit[e])
		{
			visit[e]=1;
			if(link[e]==-1||dfs(link[e]))
			{
				link[e]=k;
				return true;
			}
		}
	}
	return false;
}
int n,m,k;
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
int inmap(int x,int y)//判断附近点是否可构成边 
{
	if(x>=1&&x<=n&&y>=1&&y<=m&&!map[x][y])
	{
		return 1;
	}
	return 0;
}
int mapnum[maxn][maxn];
int nn=0;//可覆盖点的个数 
void init()//初始化 
{
	memset(visit,0,sizeof(visit));
	memset(map,0,sizeof(map));
	memset(link,-1,sizeof(link));
	memset(mapnum,0,sizeof(mapnum));
	memset(head,-1,sizeof(head));
	nn=0;
}
void build()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(map[i][j]==0)
			{
				mapnum[i][j]=++nn;//给可覆盖点编号 
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(!map[i][j])
			{
				for(int k=0;k<4;k++)//这个点上下左右的4个点点可连成一条边 
				{
					int tx=i+fx[k];
					int ty=j+fy[k];
					if(inmap(tx,ty))
					{
						add(mapnum[i][j] ,mapnum[tx][ty]);
					}
				}
			}
		}
	}
}
int main()
{
	int a,b;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		init();//初始化 
		for(int i=0;i<k;i++)
		{
			scanf("%d%d",&a,&b);
			map[b][a]=1;//有洞的点 
		}
		build();//建图 
		int ans=0;
		for(int i=1;i<=nn;i++)//匈牙利算法 
		{
			memset(visit,0,sizeof(visit));
			if(dfs(i))
			{
				ans++;
			}
		}
		if(nn%2==1||ans!=nn)//如果个数为奇数或者最大匹配数不等于点的个数 
		{
			cout<<"NO"<<endl;
		}
		else
		{
			cout<<"YES"<<endl;
		}
	}
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值