题意
n*m的矩阵中,某些地区需要放置雷达,而雷达覆盖有四种方式,上下左右,问最少的雷达数量覆盖所有*号地区。
解法
关于二分图的性质,有点晕头转向了。 和旭神讨论了。 这个题目是满足二分图的。因为对于一个雷达其关联
的地方分别为上下左右,不能够斜线。则与雷达A关联的其它雷达间是不会有联系的。所以不会形成环。可以转换成
2个集合间的关联关系。所以我们可以通过拆点法求出最大匹配。而有效顶点数量 = 最大匹配数 + 边覆盖数(最小边覆盖集)。
同时也是本题的所求的边覆盖数,既最小雷达数量。
#include<cstdio> #include<cstdlib> #include<cstring> const int N = 510; int match[N], vis[N]; int n, m; char mp[45][15]; bool edge[N][N]; int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1} }; int path( int x, int y ){ for(int i = 0; i < n; i++) for(int j = 0; j < m; j++){ if( edge[ x*m+y ][ i*m+j ] && !vis[i*m+j] ){ vis[i*m+j] = 1; if( (match[ i*m+j ] == -1) || path( match[ i*m+j ]/m, match[ i*m+j ]%m ) ){ match[ i*m+j ] = x*m+y; return 1; } } } return 0; } bool legal( int x, int y ){ if( (x>=0)&&(x<n)&&(y>=0)&&(y<m) ) return true; return false; } int main(){ int T; scanf("%d",&T); while( T-- ){ scanf("%d%d",&n,&m); for(int i = 0; i < n; i++) scanf("%s", mp[i] ); memset( edge, 0, sizeof(edge)); int tot = 0; for(int i = 0; i < n; i++) for(int j = 0; j < m; j++){ if( mp[i][j] == '*' ){ tot++; for(int k = 0; k < 4; k++){ int x = i+dir[k][0], y = j+dir[k][1]; if( legal(x,y) && (mp[x][y] == '*') ) edge[ i*m+j ][ x*m+y ] = 1; } } } int res = 0; memset( match, -1, sizeof(match)); for(int i = 0; i < n; i++){ for(int j = 0; j < m; j++){ if( mp[i][j] == '*' ){ memset( vis, 0, sizeof(vis)); res += path( i, j ); } } } // printf("tot = %d, res = %d\n", tot, res ); printf("%d\n", tot - res/2 ); // for(int i = 0; i < n*m; i++) // printf("(%d,%d): match = %d\n", i/m, i%m, match[i] ); } return 0; }