题意:一个矩形格子里,有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; }