【图论】【poj 3020】Antenna Placement

问题

给定你一个n*m的图,图中有些‘*’点,其他是‘0’点,在每个‘*’点可以建雷达,每个雷达可以覆盖其上下左右四个方向的‘*’点之一,问你最少建多少雷达,可以将这些‘*’点全部覆盖。

分析

二分图,构图,如果我们把每个‘*’点虚拟成一个节点,分布在二分图的两侧。然后,如果两点能相互覆盖,我们就在两点之间连一条边。要求的问题就转化成了,二分图最小边覆盖!

为什么是二分图呢,以为每个点只能覆盖出自身之外的一个节点,这恰好满足匹配的定义。

怎样求解二分图中的最小边覆盖呢。我们知道,一个匹配可以覆盖到2个不同的节点,那么二分图最大匹配覆盖到的节点数=最大匹配数*2。还没有被覆盖到的节点=总共的节点数-最大匹配数*2。所以,二分图最小边覆盖=最大匹配数+总共的节点数-最大匹配数*2=总的的节点数-最大匹配数

code

program liukeke;
type pig=record
     x,y:longint;
end;

var
  a:array[1..1000,0..1000] of longint;
  pos:array[1..1000] of pig;
  match:array[1..1000] of longint;
  v:array[1..1000] of boolean;
  i,zu,ans,tot,n,m,j:longint;

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);
	  if ch='*' then
	  begin
	    inc(tot);
		pos[tot].x:=i;
		pos[tot].y:=j;
	  end;
        end;
     readln;
  end;
  for i:=1 to tot do
    for j:=1 to tot do
	if i<>j then
	begin
          if ((abs(pos[i].x-pos[j].x)=1) and(abs(pos[i].y-pos[j].y)=0))or
             ((abs(pos[i].x-pos[j].x)=0) and(abs(pos[i].y-pos[j].y)=1))then
	   begin
	     inc(a[i,0]);
             a[i,a[i,0]]:=j;
	   end;
	end;
end;

function dfs(s:longint):boolean;
var
  i:longint;
begin
  for i:=1 to a[s,0] do
    if not v[a[s,i]] then
	begin
	  v[a[s,i]]:=true;
	  if (match[a[s,i]]=0)or(dfs(match[a[s,i]]))then
	  begin
	    match[a[s,i]]:=s;
		exit(true);
	  end;
	end;
  exit(false);
end;

begin
  readln(zu);
  for i:=1 to zu do
  begin
    fillchar(a,sizeof(a),0);
	fillchar(pos,sizeof(pos),0);
	fillchar(match,sizeof(match),0);
    tot:=0;
	ans:=0;
    init;
	for j:=1 to tot do
	begin
	  fillchar(v,sizeof(v),false);
	  if dfs(j) then inc(ans);
	end;
	writeln(tot-ans>>1);
  end;
end.
posted @ 2011-03-20 20:55  liukee  阅读(248)  评论(0编辑  收藏  举报