【codevs 1022】覆盖(匈牙利算法)

1022 覆盖

 时间限制: 1 s  空间限制: 128000 KB 题目等级 : 大师 Master

题目描述 Description

    有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地。如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分重叠)这个陆地,那么最多可以覆盖多少陆地面积。

输入描述 Input Description

    输入文件的第一行是两个整数N、M(1<=N,M<=100),第二行为一个整数K( K<=50),接下来的K行,每行两个整数X,Y表示K个水塘的行列位置。(1<=X<=N,1<=Y<=M)。 

输出描述 Output Description

    输出所覆盖的最大面积块(1×2面积算一块)。

样例输入 Sample Input

    4 4

    6

    1 1

    1 4

    2 2

    4 1

    4 2

    4 4

样例输出 Sample Output

    4

 【题解】【匈牙利算法】

【将可能被一起覆盖的方格之间连边,构成一个二分图,用dfs求出一边的点(类似于上一道题),然后跑匈牙利算法】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int d[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int a[20010],nxt[20010],p[10010],tot;
int mp[110][110],f[10010],opt[10010];
int n,m,k,tt,ans;
bool ch[110][110],vis[10010];
inline void add(int x,int y)
{
	tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot;
}
bool dfs(int x)
{
	for(int i=p[x];i!=-1;i=nxt[i])
	 if(!vis[a[i]])
	  {
	  	vis[a[i]]=1;
	  	if(f[a[i]]==-1||dfs(f[a[i]]))
	  	 {
	  	 	f[a[i]]=x;
	  	 	return 1;
		   }
	  }
	return 0;
}
void type(int x,int t)
{
	vis[x]=1; opt[x]=t;
	for(int i=p[x];i!=-1;i=nxt[i])
	 if(!vis[a[i]]) type(a[i],t^1);
}
int main()
{
	int i,j;
	memset(p,-1,sizeof(p));
	memset(f,-1,sizeof(f));
	memset(opt,-1,sizeof(opt));
	memset(nxt,-1,sizeof(nxt));
	scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<=k;++i)
	 {
	 	int x,y;
	 	scanf("%d%d",&x,&y);
	 	ch[x][y]=1;
	 }
	for(i=1;i<=n;++i)
	 for(j=1;j<=m;++j)
	  if(!ch[i][j]) mp[i][j]=++tt;
	for(i=1;i<=n;++i)
	 for(j=1;j<=m;++j)
	  if(!ch[i][j])
	   {
	   	    int x=i,y=j;
	   	    for(int l=0;l<4;++l)
	   	     {
	   	     	int xx=x+d[l][0],yy=y+d[l][1];
	   	     	if(xx>0&&xx<=n&&yy>0&&yy<=m&&!ch[xx][yy])
	   	     	 add(mp[x][y],mp[xx][yy]);
				} 
	   }
	for(i=1;i<=tt;++i)
	 if(!vis[i]) type(i,0);
	for(i=1;i<=tt;++i)
	 if(!opt[i])
	  {
	 	memset(vis,0,sizeof(vis));
	 	if(dfs(i)) ans++;
	   }  
	printf("%d\n",ans);
	return 0;
}

转载于:https://www.cnblogs.com/lris-searching/p/9402959.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值