行列覆盖,最小点集覆盖

【题目】:Muddy Fields
【类型】:图论
【难度】:3
【来源】:PKU 2226
【关键字】:二分图匹配 行列【题目】:Muddy Fields
【类型】:图论
【难度】:3
【来源】:PKU 2226
【关键字】:二分图匹配 行列覆盖 最小点集覆盖

【题目大意】:N行M列的地,*代表泥地,.代表草地。你必须用宽为1,长度不限的木板将泥地覆盖住,且不能覆盖草地。问最少需要几块木板。

【分析】:

如果是普通的行列覆盖,则我们将行作为元素,将列作为元素,进行二分图匹配,即可求出行列覆盖。

但是,若不能覆盖到草地。我们则需要重新构图。

原来的构图是将整行整列作为元素,那么加入限制后,我们可以将每一行连通的块作为元素,先进行标号,再按原来的方式进行构图即可。

【时间复杂度】:O(N^2*M^2)
覆盖 最小点集覆盖

【题目大意】:N行M列的地,*代表泥地,.代表草地。你必须用宽为1,长度不限的木板将泥地覆盖住,且不能覆盖草地。问最少需要几块木板。

【分析】:

如果是普通的行列覆盖,则我们将行作为元素,将列作为元素,进行二分图匹配,即可求出行列覆盖。

但是,若不能覆盖到草地。我们则需要重新构图。

原来的构图是将整行整列作为元素,那么加入限制后,我们可以将每一行连通的块作为元素,先进行标号,再按原来的方式进行构图即可。

【时间复杂度】:O(N^2*M^2)

var n,m,ans,tot1,tot2:longint;
    a:array[0..maxn,0..maxn] of boolean;
    g:array[0..maxm,0..maxm] of boolean;
    row,col:array[0..maxn,0..maxn] of longint;
    v:array[0..maxm] of boolean;
    link:array[0..maxm] of longint;
//=================================================================
function find(x:longint):boolean; {匈牙利算法}
var i:longint;
begin
 for i:=1 to tot2 do
 if (not v[i])and(g[x,i]) then
 begin
  v[i]:=true;

  if (link[i]=0)or(find(link[i])) then
  begin
   link[i]:=x;
   exit(true);
  end;
 end;

 exit(false);
end;
//=================================================================
procedure init; {读入,构图}
var i,j:longint;
    ch:char;
begin
 readln(n,m);

 for i:=1 to n do
 begin
  for j:=1 to m do
  begin
   read(ch);
   a[i,j]:=ch='*';
  end;

  readln;
 end;

 tot1:=0; {对每行的连通块进行标号}
 for i:=1 to n do
 begin
  for j:=1 to m do
  if a[i,j] then
  begin
   if (j=1)or(not a[i,j-1]) then inc(tot1);
   row[i,j]:=tot1;
  end;
 end;

 tot2:=0; {对每列的连通块进行标号}
 for j:=1 to m do
 begin
  for i:=1 to n do
  if a[i,j] then
  begin
   if (i=1)or(not a[i-1,j]) then inc(tot2);
   col[i,j]:=tot2;
  end;
 end;

 for i:=1 to n do {以行列为元素构图连边}
 for j:=1 to m do
 g[row[i,j],col[i,j]]:=true;
end;
//=================================================================
procedure main; {主函数}
var i:longint;
begin
 fillchar(link,sizeof(link),0);
 ans:=0;
 for i:=1 to tot1 do {匹配}
 begin
  fillchar(v,sizeof(v),false);
  find(i);
 end;

 for i:=1 to tot2 do {统计}
 if link[i]<>0 then inc(ans);

 writeln(ans); {输出}
end;
//=================================================================
begin
 assign(input,'p2226.in'); reset(input);
 assign(output,'p2226.out'); rewrite(output);
 while not eof do
 begin
  init;
  main;
 end;
 close(input); close(output);
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值