USACO The Castle(flood fill)

题目请点我


题解:

这道题真的好蛋疼啊,首先题意不好理解,搞了半天复杂的要死,有那么多要求,还要求那么多东西,做到一半都不想做了。。。感觉没什么技术含量,还做起来死费劲儿。但是强迫症非得按顺序做题啊,最后还是一点点把它给调出来了,说什么flood fill,其实也就是那么回事,没什么算法上的技巧,就是见招拆招的感觉。。。

题意搞懂再做题,题意,不谢!

第一步:根据他的规则把房间画出来,遍历一遍把每个节点四面的墙给补上;

第二步:深搜;

目的1:记录深搜的次数,房间数;

目的2:记录深搜的深度,最大房间面积;

目的3:把属于同一棵树的节点标记起来,也就是染色的过程,为下一步打通房间铺路;

注意:在深搜的过程中搜的深度要注意如何保存,会有分叉以及分叉后再汇合的情况出现,我是设置了一个全局变量deep来记录深度;

第三步:打墙;

题目说了,只能打一次,而且还有规则,先紧着西边的选,如果同样靠西要先紧着南边的选,所以要注意遍历的方向。打墙的时候就凸显之前标色的重要性了,首先得找到墙,然后墙两边的颜色还要不一样,从下往上,从左往右遍历一遍找到最优解。

PS:注意数组大小。


代码实现:

/*
ID: eashion
LANG:C++
TASK:castle
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define MAX 55

using namespace std;

int N,M;
int Sum;
int Size;
int deep;
int BSize;
int bx,by;
int color;
int Csize[MAX*MAX];
char oritation;
int maze[MAX][MAX];
int dx[4] = {1,0,-1,0};
int dy[4] = {0,-1,0,1};
int castle[MAX*3][MAX*3];
void solve();
void dfs(int x,int y,int col);
void Break();
int main()
{
    freopen("castle.in","r",stdin);
    freopen("castle.out","w",stdout);
    scanf("%d%d",&M,&N);
    for( int i = 1; i <=N; i++ ){
        for( int j = 1; j <= M; j++ ){
            scanf("%d",&maze[i][j]);
        }
    }
    solve();
    return 0;
}

void solve(){
    Sum = 0;
    Size = 0;
    BSize = 0;
    color = 2;
    memset(Csize,0,sizeof(Csize));
    memset(castle,0,sizeof(castle));
    //补墙,用到了&运算
    for( int i = 1; i <= N; i++ ){
        for( int j = 1; j <= M; j++ ){
            int tx = i*2-1;
            int ty = j*2-1;
            if( (maze[i][j]&1) == 1 ){
                castle[tx][ty-1] = 1;
            }
            if( (maze[i][j]&2) == 2 ){
                castle[tx-1][ty] = 1;
            }
            if( (maze[i][j]&4) == 4 ){
                castle[tx][ty+1] = 1;
            }
            if( (maze[i][j]&8) == 8 ){
                castle[tx+1][ty] = 1;
            }
        }
    }
    //补四面的墙
    for( int i = 0; i <= 2*N; i++ ){
        castle[i][0] = 1;
    }
    for( int i = 0; i <= 2*N; i++ ){
        castle[i][2*M] = 1;
    }
    for( int i = 0; i <= 2*M; i++ ){
        castle[0][i] = 1;
    }
    for( int i = 0; i <= 2*M; i++ ){
        castle[2*N][i] = 1;
    }
    //补节点处的墙,其实也不太会访问到
    for( int i = 2; i <= 2*N; i+=2 ){
        for( int j = 2; j <= 2*M; j+=2 ){
            castle[i][j] = 1;
        }
    }
//    for( int i = 0; i <= 2*N; i++ ){
//        for( int j = 0; j <= 2*M; j++ ){
//            printf("%d",castle[i][j]);
//        }
//        printf("\n");
//    }
    //深搜
    for( int i = 1; i <= N; i++ ){
        for( int j = 1; j <= M; j++ ){
            int tx = i*2-1;
            int ty = j*2-1;
            deep = 0;
            if( castle[tx][ty] == 0 ){
                dfs(tx,ty,color++);
                Csize[color-1] = deep;
                Sum++;
                Size = max(Size,deep);
            }
        }
    }
    //打墙
    Break();
    printf("%d\n",Sum);
    printf("%d\n",Size);
    printf("%d\n",BSize);
    printf("%d %d %c\n",bx,by,oritation);
}

void dfs(int x,int y,int col){
    //每进入一次深度+1
    deep++;
    //标色
    castle[x][y] = col;
    for( int i = 0; i < 4; i++ ){
        int nx = x+dx[i];
        int ny = y+dy[i];
        int nnx = nx+dx[i];
        int nny = ny+dy[i];
        //必须保证两个同时为0,因为下个节点可能会已经被染色,导致重复染色
        if( castle[nx][ny] == 0 && castle[nnx][nny] == 0 ){
            castle[nx][ny] = col;
            dfs(nnx,nny,col);
        }
    }
    return ;
}

void Break(){
    //注意遍历顺序
    for( int j = 0; j <= 2*M; j++ ){
        for( int i = 2*N; i >= 0; i-- ){
            if( castle[i][j] == 1 ){
                int ux,uy;
                int dx,dy;
                int rx,ry;
                int lx,ly;
                ux = i-1,uy = j;
                dx = i+1,dy = j;
                rx = i,ry = j+1;
                lx = i,ly = j-1;
                //上下打通
                if( ux >= 0 && dx <= 2*N && castle[ux][uy]!=castle[dx][dy] ){
                    int tmp = Csize[castle[ux][uy]]+Csize[castle[dx][dy]];
                    if( BSize < tmp ){
                        BSize = tmp;
                        bx = (dx+1)/2;
                        by = (dy+1)/2;
                        oritation = 'N';
                    }
                }
                //左右打通
                if( ly >= 0 && ry <= 2*M && castle[lx][ly]!=castle[rx][ry] ){
                    int tmp = Csize[castle[lx][ly]]+Csize[castle[rx][ry]];
                    if( BSize < tmp ){
                        BSize = tmp;
                        bx = (lx+1)/2;
                        by = (ly+1)/2;
                        oritation = 'E';
                    }
                }
                //把上下放前面,而且严格BSize < tmp,保证了若有可能先打‘N’
            }
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值