覆盖_codevs1022_匹配

99 篇文章 0 订阅
30 篇文章 0 订阅

题目描述 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.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值