poj 3020 Antenna Placement 边覆盖数/最小边覆盖集

题意

  n*m的矩阵中,某些地区需要放置雷达,而雷达覆盖有四种方式,上下左右,问最少的雷达数量覆盖所有*号地区。

 

解法

  关于二分图的性质,有点晕头转向了。 和旭神讨论了。 这个题目是满足二分图的。因为对于一个雷达其关联

的地方分别为上下左右,不能够斜线。则与雷达A关联的其它雷达间是不会有联系的。所以不会形成环。可以转换成

2个集合间的关联关系。所以我们可以通过拆点法求出最大匹配。而有效顶点数量 = 最大匹配数 + 边覆盖数(最小边覆盖集)。 

同时也是本题的所求的边覆盖数,既最小雷达数量。

View Code
#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;    
}

 

posted @ 2013-03-31 16:57  yefeng1627  阅读(258)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor