zoj 1654 Place the Robots#匈牙利算法#

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/79981007

题目

放置最多的机器人,使它们不相互攻击。


分析

首先我们可以想到的,是最大独立集(图1)。
这里写图片描述
——(图1)——
只要判断这些空地是否受到影响就可以了。
But 这种效率太低了,所以我们要考虑如何优化图。
这里写图片描述 (图2)行连通块
这里写图片描述 (图3)列连通块
如果这些连通块连在一起,那么必然不能放。


代码

#include <iostream>
using namespace std;
struct node{short y,next;}e[1562501]; int answer;
const short d[2]={1,-1}; char map[1251][1251]; bool cover[1251];
short ls[1251],link[1251],t,n,m,k,v1[1251][1251],v2[1251][1251];
bool check(short x,short y){return !(x<1||y<1||x>n||y>m||map[x][y]=='#');}
void add(short x,short y){e[++k].y=y; e[k].next=ls[x]; ls[x]=k;}
bool find(short x){
    short t=ls[x];
    while (t){
        if (!cover[e[t].y]){
            cover[e[t].y]=1;
            short q=link[e[t].y];
            link[e[t].y]=x;
            if (!q||find(q)) return 1;
            link[e[t].y]=q;
        }
        t=e[t].next;
    }
    return 0;
}
int main(){
    ios::sync_with_stdio(0);
    cin>>t;
    while (t--){
        fill(ls,ls+1251,0);
        fill(link,link+1251,0);
        cin>>n>>m; int m1=0,ans=0,m2=0;
        for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        cin>>map[i][j],v1[i][j]=0,v2[i][j]=0;
        for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        if (map[i][j]=='o'){
            if (!v1[i][j]){
            v1[i][j]=++m1;
            for (int k=0;k<2;k++){
               int step=1;
               while (check(i+d[k]*step,j)) v1[i+d[k]*step][j]=m1,step++;//往外扩张
            }
            }
            if (!v2[i][j]){
            v2[i][j]=++m2;
            for (int k=0;k<2;k++){
               int step=1;
               while (check(i,j+d[k]*step)) v2[i][j+d[k]*step]=m2,step++;//往外扩张
            }
            }
        }
        for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        if (v1[i][j]&&v2[i][j]&&map[i][j]=='o') add(v1[i][j],v2[i][j]);//连在一起
        for (int i=1;i<=m1;i++) fill(cover,cover+1251,0),
        ans+=find(i);
        cout<<"Case :"<<++answer<<endl<<ans<<endl;
    }
    return 0;
}

ZJU 1654 Place the Robots(二分图)

04-16

Robert is a famous engineer. One day he was given a task by his boss. The background of the task was the following:rnrnGiven a map consisting of square blocks. There were three kinds of blocks: Wall, Grass, and Empty. His boss wanted to place as many robots as possible in the map. Each robot held a laser weapon which could shoot to four directions (north, east, south, west) simultaneously. A robot had to stay at the block where it was initially placed all the time and to keep firing all the time. The laser beams certainly could pass the grid of Grass, but could not pass the grid of Wall. A robot could only be placed in an Empty block. Surely the boss would not want to see one robot hurting another. In other words, two robots must not be placed in one line (horizontally or vertically) unless there is a Wall between them.rnrnNow that you are such a smart programmer and one of Robert's best friends, He is asking you to help him solving this problem. That is, given the description of a map, compute the maximum number of robots that can be placed in the map.rnrnrnInputrnrnThe first line contains an integer T (<= 11) which is the number of test cases. rnrnFor each test case, the first line contains two integers m and n (1<= m, n <=50) which are the row and column sizes of the map. Then m lines follow, each contains n characters of '#', '*', or 'o' which represent Wall, Grass, and Empty, respectively. rnrnrnOutputrnrnFor each test case, first output the case number in one line, in the format: "Case :id" where id is the test case number, counting from 1. In the second line just output the maximum number of robots that can be placed in that map.rnrnrnSample Inputrnrn2rn4 4rno***rn*###rnoo#orn***orn4 4rn#ooorno#oornoo#orn***#rnrnrnSample OutputrnrnCase :1rn3rnCase :2rn5rnrnhttp://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=654rnrn rnrn rnrn算法: 不要用搜索来解这道题, 可以灵活运用二分图的想法,构造邻接矩阵。。将横着的没有被阻挡的块合并成一个大块。将竖着的没有被阻挡的块合并成一个大块。 这样得到若干个横向块,和纵向块,如果一横向块与纵向块之间有共同的点,那么就将这两个大块连线(构造一个横向块与纵向块的邻接矩阵)。 构造好之后就可以算横向块与纵向块的最大匹配数。这个数就是机器人的可以摆放的个数。。rnrn rnrn rnrn代码:rnrn#include rnusing namespace std;rnrnstruct XBlockrnrn int x;rn int starty, endy;rn;rnrnstruct YBlockrnrn int y;rn int startx, endx;rnrn;rnrnXBlock bx[2501];rnYBlock yb[2501];rnchar map[51][51];rnchar temp[51][51];rnint casen, n, m, bxn, byn, match;rnbool connect[2501][2501];rnbool state[1501];rnint res[1501];rnrnvoid copy()rnrn int i,j;rn for( i = 1; i <= n ; i++)rn for( j = 1; j <= m; j++)rn temp[i][j] = map[i][j];rnrnrnvoid MakeXBlock()rnrn int i, j, t;rn bxn = 0; //记录bx[]的下标rn for( i = 1; i <= n ; i++)rn for( j = 1; j <= m; j++)rn if(temp[i][j] == 'o')rn rn bxn ++;rn bx[bxn].x = i;rn for( t = j; t > 0; t--)//确定横向块的起始坐标rn rn if(temp[i][t] == '#')rn rn bx[bxn].starty = t+1; rn break;rn rn elsern rn bx[bxn].starty = t;rn if(temp[i][t] == 'o' && t != j) //删除这一块中的其他‘o’rn temp[i][t] = 'x';rn rn rnrn for( t = j; t <= m; t++ )//确定横向块的结束坐标rn rn if(temp[i][t] == '#')rn rn bx[bxn].endy = t-1; rn break;rn rn elsern rn bx[bxn].endy = t;rn if(temp[i][t] == 'o' && t != j ) //删除这一块中的其他‘o’rn temp[i][t] = 'x';rn rn rnrn rnrnrnvoid MakeYBlock()rnrn int i, j, t;rn byn = 0;rn for(j = 1; j <= m ;j++)rn for(i = 1; i <= n; i++)rn if(temp[i][j] == 'o')rn rn byn++;rn yb[byn].y = j;rn for(t = i ; t > 0 ; t--) //确定纵向块的起始坐标rn rn if(temp[t][j] == '#')rn rn yb[byn].startx = t+1; rn break;rn rn elsern rn yb[byn].startx = t;rn if(temp[t][j] == 'o' && t != i) //删除这一块中的其他‘o’rn temp[t][j] = 'x';rn rn rnrn for( t = i; t <= n; t++ )//确定纵向快的结束坐标rn rn if(temp[t][j] == '#')rn rn yb[byn].endx = t-1; rn break;rn rn elsern rn yb[byn].endx = t;rn if(temp[t][j] == 'o' && t != i ) //删除这一块中的其他‘o’rn temp[t][j] = 'x';rn rn rn rnrnbool find(int i) //匈牙利算法,进行最大匹配计算rnrn int j;rn for(j = 1; j <= byn; j++)rn if(connect[i][j] == true && state[j] == false)rn rn state[j] = true;rn if(res[j] == 0 || find (res[j]) == true)rn rn res[j] = i;rn return true;rn rn rn return false;rnrnrnrnint main()rnrn cin>>casen;rn int i, j, num = casen;rn while(num--)rn rn cin>>n>>m;rn for( i = 1; i <= n ; i++)rn for( j = 1; j <= m; j++)rn cin>>map[i][j];rnrn for( i = 1; i <= 1500; i++) // 初始化结构体里的坐标rn rn bx[i].endy = bx[i].starty = bx[i].x = 0;rn yb[i].endx = yb[i].startx = yb[i].y = 0;rn rn copy(); rn MakeXBlock();//构造横向块rn copy();rn MakeYBlock(); //构造纵向块rn memset(connect, false, sizeof(connect));rn memset(res, 0 , sizeof(res));rn for(i = 1; i <= bxn; i++) //构造邻接矩阵rn for(j = 1; j <= byn; j++)rn rn if((bx[i].x >= yb[j].startx && bx[i].x <= yb[j].endx) &&( yb[j].y >= bx[i].starty && yb[j].y <= bx[i].endy ))rn connect[i][j] = true;rn rn match = 0;rn for(i = 1; i <= bxn; i++) //计算最大匹配数rn rn memset(state, false, sizeof(state));rn if(find(i))rn match++;rn rn cout<<"Case :"<

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试

关闭