题目描述 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面积算一块)
题解
一次A感♂觉♂很♂好啊(其实是两次)
裸的最大匹配,匈牙利算法然后就这么过了
最后输出的时候面积算(ans+1)/2
源码
#include <stdio.h>
#include <cstring>
using namespace std;
struct edge
{
int x,y,next;
};
edge e[51];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
bool v[51];
int n,m,k,maxE=0,count=0;
int map[51][51]={};
int link[51],ls[51];
void add(int x,int y)
{
e[++maxE].x=x;
e[maxE].y=y;
e[maxE].next=ls[x];
ls[x]=maxE;
}
bool find(int x)
{
for (int i=ls[x];i;i=e[i].next)
if (!v[e[i].y])
{
int p=link[e[i].y];
link[e[i].y]=x;
v[e[i].y]=true;
if (!p||find(p))
return true;
link[e[i].y]=p;
}
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
map[x][y]=-1;
}
for (int i=1;i<n;i++)
for (int j=1;j<m;j++)
if (!map[i][j])
map[i][j]=++count;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int l=0;l<4;l++)
if (map[i+dx[l]][j+dy[l]]>0&&map[i][j]>0)
add(map[i+dx[l]][j+dy[l]],map[i][j]);
for (int i=1;i<=count;i++)
{
memset(v,false,sizeof(v));
find(i);
}
int ans=0;
for (int i=1;i<=count;i++)
if (link[i])
ans++;
printf("%d\n",(ans+1)/2);
return 0;
}
type
edge=record
x,y,next:longint;
end;
const
dx:array[1..4]of integer=(-1,1,0,0);
dy:array[1..4]of integer=(0,0,-1,1);
var
n,m,p,count,maxE:longint;
map,q:array[0..100,0..100]of longint;
link,ls:array[0..1000]of longint;
v:array[0..1000]of boolean;
e:array[0..1000]of edge;
procedure add(x,y:longint);
begin
inc(maxE);
e[maxE].x:=x;
e[maxE].y:=y;
e[maxE].next:=ls[x];
ls[x]:=maxE;
end;
function find(x:longint):boolean;
var
i,k:longint;
begin
find:=true;
i:=ls[x];
while i>0 do
with e[i] do
begin
if not v[y] then
begin
k:=link[y];
link[y]:=x;
v[y]:=true;
if (k=0)or find(k) then exit;
link[y]:=k;
end;
i:=next;
end;
find:=false;
end;
procedure main;
var
i,ans:longint;
begin
ans:=0;
fillchar(link,sizeof(link),0);
for i:=1 to count do
begin
fillchar(v,sizeof(v),false);
find(i);
end;
for i:=1 to count do
if link[i]<>0 then inc(ans);
writeln((ans+1) div 2);
end;
procedure init;
var
i,j,k,x,y:longint;
begin
fillchar(ls,sizeof(ls),0);
fillchar(e,sizeof(e),0);
readln(n,m);
readln(p);
count:=0;
maxE:=0;
for i:=1 to p do
begin
readln(x,y);
map[x,y]:=1;
end;
for i:=1 to n do
for j:=1 to m do
if map[i,j]=0 then
begin
inc(count);
q[i,j]:=count;
end;
for i:=1 to n do
for j:=1 to m do
for k:=1 to 4 do
if (map[i,j]=0)and(map[i+dx[k],j+dy[k]]=0) then
add(q[i,j],q[i+dx[k],j+dy[k]]);
end;
begin
init;
main;
end.