zoj 1654 Place the Rebots 最大独立集转换成二分图最大独立边(最大匹配)

题意

  N*M矩阵,有空地('o')、草地('*')、墙('#‘),机器人能攻击到上下左右,不被墙挡住的方位。

并且机器人只能被放置在空地上。问能放置的最大数量机器人,相互间不能攻击到。

 

解题思路

  对于所有空地,能够攻击到的相互之间冲突,即可连接成边,然后题目就转换成了 最大独立集问题。

但是本题 顶点数量为 50*50 = 2500, 果断TLE。

  另外我们可以发现,通过

    将每一行相互攻击到的空格位置看成一个点,这些点命名为 {A}

    将每一列相互攻击到的空格位置看成一个点,这些点命名为 {B}

  则图就转换了二分图, 对于 顶点集 {A} 与 {B} 而言, 之间存在共用的空格,则其相互间存在冲突,则当前点只能放一个机器人。

则通过将其连边, 那么问题就转换成了求 没有公共顶点的最大边集(最大匹配)。

#include<cstdio>

#include<cstring>

#include<cstdlib>



const int N = 51;



char mp[N][N];

int n, m;

int row,col,r[N][N],c[N][N];

bool g[N*N][N*N];

int ma[N*N], mb[N*N];

bool vis[N*N];



void init(){

    memset(r,0,sizeof(r));

    memset(c,0,sizeof(c));

    memset(g,0,sizeof(g));

    row = col = -1;

    bool flag = false;

    for(int i = 0; i < n; i++){

        flag = false;

        for(int j = 0; j < m; j++){

            if( mp[i][j] == 'o' ){

                if(!flag) ++row;

                r[i][j] = row, flag = true;

            }    

            else if( mp[i][j] == '#' ) flag = false;

        }    

    }

    for(int j = 0; j < m; j++){

        flag = false;

        for(int i = 0; i < n; i++){

            if( mp[i][j] == 'o' ){ 

                if( !flag ) ++col;

                c[i][j] = col, flag = true;

            }    

            else if( mp[i][j] == '#' ) flag = false;

        }    

    }

    col++; row++;

    for(int i = 0; i < n; i++)

        for(int j = 0; j < m; j++)

            if( mp[i][j] == 'o' )

                g[ r[i][j] ][ c[i][j] ] = 1;

}



int path( int u ){

    for(int v = 0; v < col; v++){

        if( g[u][v] && !vis[v] ){

            vis[v] = 1;

            if( ma[v] == -1 || path( ma[v] ) ){

                ma[v] = u; mb[u] = v;

                return 1;    

            }

        }

    }    

    return 0;

}

void MaxMatch(){

    memset( ma,0xff,sizeof(ma));

    memset( mb,0xff,sizeof(mb));

    int res = 0;

    for(int i = 0; i < row; i++){

        if( mb[i] == -1 ){

            memset( vis, 0, col*sizeof(int));    

            res += path( i );

        }

    }    

    printf("%d\n", res );

}

int main(){

    int T;

    scanf("%d", &T);

    for(int Case = 1; Case <= T; Case++){

        scanf("%d%d", &n,&m);

        for(int i = 0; i < n; i++)

            scanf("%s",mp[i]);

        printf("Case :%d\n", Case);

        init();

        MaxMatch();

    }    

    return 0;

}

 

你可能感兴趣的:(二分图)