zoukankan      html  css  js  c++  java
  • 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;    
    }
  • 相关阅读:
    JAVA调用WCF
    写代码之前要做什么?
    漫谈界面和数据
    UIButton 简易的UI
    数据结构利器之私房STL(中)
    有趣的位运算
    基于TCP的C/S初级网络编程1
    数据结构利器之私房STL(上)
    Unix/Linux 那些系统启动后的进程
    【字符串匹配】KMP算法之道
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2991912.html
Copyright © 2011-2022 走看看