POJ 3020题
类型:二分匹配
题目大意:一个矩形中,有N个城市,现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市。
问至少放置多少个基站才能使得所有的城市都覆盖无线?
解题思路:最大匹配数+城市总数-(最大匹配数*2) ,最大匹配数代表每个基站覆盖两个城市,其余的城市用一个基站覆盖
其中最大匹配数的求解,对顶点数不分左右子集,将左右子集都等于所有定点,最后将得出的匹配除以二则得到真正的匹配
二分图的构造是对*编号,然后给相邻的*连双向边,对*构造二分图
最大匹配:使用匈牙利算法
从这道题得出了一个结论:所有顶点的匹配等于左右子集匹配的2倍
#include <iostream>
#include <string>
//#include <conio.h>
using namespace std;
int h,w;
#define arraysize 401
#define hsize 41
#define wsize 11
int map[arraysize][arraysize];
bool final[arraysize];
int match[arraysize];
string tempmap[hsize];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; //定义4个方向
bool DFS(int p)
{
int i;
int temp;
for(i=0;i<h*w;++i)
{
if(map[p][i] && !final[i])
{
final[i] = true;
temp = match[i];
match[i] = p;
if(temp==0 || DFS(temp)) return true;
match[i] = temp;
}
}
return false;
}
int mat()
{
int i,j;
int maxmatch = 0;
for(i=0;i<h*w;++i)
{
memset(final,0,sizeof(final));
if(DFS(i)) maxmatch++;
}
return maxmatch;
}
int main()
{
//freopen("1.txt","r",stdin);
int t;
int i,j,k,e;
string str;
int total;
cin>>t;
while(t--)
{
total=0;
memset(map,0,sizeof(map));
memset(match,0,sizeof(match));
cin>>h>>w;
for(i=0;i<h;++i) //i行
{
cin>>tempmap[i];
}
for(i=0;i<h;++i) //i行
{
for(j=0;j<w;++j) //j列
{
if(tempmap[i][j]=='*')
{
total++;
for(k=0;k<4;++k)
{
int tempr = i+dir[k][0];
int tempc = j+dir[k][1];
if(tempr>=0 && tempr <h && tempc>=0 && tempc<w && tempmap[tempr][tempc]=='*')
{
map[i*w+j][tempr*w+tempc] = 1;
}
}
}
}
}
cout<<(total-mat()/2)<<endl;
}
//getch();
return 0;
}