向前走莫回头❤

【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;
}

posted @ 2016-11-10 23:44  lris0-0  阅读(76)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m