题意:一个矩形格子里,有n个城市,现在这n个城市都要覆盖无线。对于任意一个基站,它可以覆盖任意相邻的两个格子。那么如和建立基站,才能使所有的城市都被覆盖,并且所用的基站数量最少?
题解:把城市看作点,相邻的两个城市之间连一条边。若a,b间存在一条边,那么a,b可以用同一个基站覆盖,而那些单独剩下的每一个点都必须用一个基站来覆盖。
所以总的基站个数 = 最小边覆盖 = 最大二分匹配 + 最大独立集。但是在二分图中,左半图的集合和右半图的集合实质上是同一个集合,所以集合的每一个点都被覆盖了两次。
假如左半图集合为X,右半图集合为Y,最大匹配数为M,则|X| = |Y|, 基站个数 = [M + (|X| - M + |Y| - M)] / 2 = |X| - M/2;
下面给出了两种实现方式:
#include <iostream>
using namespace std;
char matrix[50][15];
bool map[500][500],vis[500];
int match[500];
int dir[4][2] = {{-1,0},{1,0},{0,1},{0,-1}};
int h,w;
bool find_path ( int t )
{
int r, c, pos;
for ( int i = 0; i < 4; i++ )
{
r = t / w + dir[i][0];
c = t % w + dir[i][1];
pos = r * w + c;
if ( r >= 0 && r < h && c >= 0 && c < w && map[t][pos] && !vis[pos] )
{
vis[pos] = true;
if ( match[pos] == -1 || find_path ( match[pos] ) )
{
match[pos] = t;
return true;
}
}
}
return false;
}
int Hungary()
{
int ans = 0;
memset(match,-1,sizeof(match));
for ( int i = 0; i < w * h; i++ )
{
memset(vis,0,sizeof(vis));
if ( find_path(i) )
ans++;
}
return ans;
}
int main()
{
int i, j, k, r, c, t, cnt;
scanf("%d",&t);
while ( t-- )
{
scanf("%d%d",&h,&w);
for ( i = 0; i < h; i++ )
scanf("%s",matrix[i]);
cnt = 0;
memset(map,0,sizeof(map));
for ( i = 0; i < h; i++ )
{
for ( j = 0; j < w; j++ )
{
if ( matrix[i][j] == 'o' )
continue;
for ( k = 0; k < 4; k++ )
{
r = i + dir[k][0];
c = j + dir[k][1];
if ( r >= 0 && r < h && c >= 0 && c < w && matrix[r][c] == '*' )
map[i*w+j][r*w+c] = true;
}
cnt++;
}
}
printf("%d\n", cnt - Hungary() / 2 );
}
return 0;
}
#include <iostream>
using namespace std;
int match[500];
int dir[4][2] = {{-1,0},{1,0},{0,1},{0,-1}};
bool map[500][500],vis[500];
int h, w, cnt;
struct
{
char ch;
int id;
} matrix[50][15];
bool find_path ( int t )
{
for ( int i = 1; i <= cnt; i++ )
{
if ( map[t][i] && ! vis[i] )
{
vis[i] = true;
if ( match[i] == -1 || find_path ( match[i] ) )
{
match[i] = t;
return true;
}
}
}
return false;
}
int Hungary()
{
int i, ans = 0;
memset(match,-1,sizeof(match));
for ( i = 1; i <= cnt; i++ )
{
memset(vis,0,sizeof(vis));
if ( find_path(i) )
ans++;
}
return ans;
}
int main()
{
int i, j, k, r, c, t;
scanf("%d",&t);
while ( t-- )
{
scanf("%d%d",&h,&w);
cnt = 0;
for ( i = 0; i < h; i++ )
{
getchar();
for ( j = 0; j < w; j++ )
{
matrix[i][j].ch = getchar();
if ( matrix[i][j].ch == '*' )
matrix[i][j].id = ++ cnt;
}
}
memset(map,0,sizeof(map));
for ( i = 0; i < h; i++ )
{
for ( j = 0; j < w; j++ )
{
if ( matrix[i][j].ch == 'o' )
continue;
for ( k = 0; k < 4; k++ )
{
r = i + dir[k][0];
c = j + dir[k][1];
if ( r >= 0 && r < h && c >= 0 && c < w && matrix[r][c].ch == '*' )
map[ matrix[i][j].id ][ matrix[r][c].id ] = true;
}
}
}
printf("%d\n", cnt - Hungary() / 2 );
}
return 0;
}