【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;
}
既然无能更改,又何必枉自寻烦忧