poj 2056 The Separator in Grid——BFS(广度优先搜索)

The Separator in Grid

Description

Given a connected, undirected graph G = (V, E), where V is the vertex set consisting a collection of nodes, and E is the set of edges, each of which connects two nodes from V. A vertex subset S is a separator if the subgraph induced by the vertices in V, but not in S, has two connected components. We shall use the notation [S, W, B] to represent the partition, where the removal of the separator S will give two connected components W and B.

In this problem, we consider the separators in grids. Each node in a grid is connected to its eight neighbors (if they exist). In Figure-1, we illustrate a partition of a 6*6 grid with a 9-point separator (gray nodes in the figure). The nodes on the left of the separator are in set W (white nodes), and the nodes on the right of the separator are in set B (black nodes).
在这里插入图片描述

To simplify the problem, you can assume that all the separators referred in this problem satisfy the following restrictions:

  1. It’s a minimal separator. A separator is minimal if no subset of it forms a separator.
  2. It begins from a node on the top line of the grid, except the corner (i.e. 30 and 35 in the figures), and ends with a node on the bottom line of the grid, also except the corner (i.e. 0 and 5 in the figures).
  3. On its way from top to bottom, it can go left, right or down, but never go up.

Now we describe a method to improve a given partition on a grid, through which we can reduce the number of nodes in the separator. This method contains two steps:

  1. Select several nodes from B and add them into S. Any of the selected nodes must have a left neighbor which is in S.
  2. Remove several nodes from S (excluding the nodes added in the former step), and add them into W.

After the improvement, we should ensure S is still a separator, and make the number of nodes in S as small as possible. As for Figure-1, we should add 14 and 20 into S, and remove 7, 13, 19 and 25 from S. After that, we obtain a new partition with a 7-point separator shown in Figure-2.

Your task is, given a partition on a grid, to determine the least number of nodes in the separator after the improvement.

Input

There are several test cases. Each case begins with a line containing two integers, N and M (3 <= M, N <= 200). In each of the following N lines, there are M characters, describing the initial partition of the M*N grid. Every character is ‘S’, ‘W’ or ‘B’. It is confirmed that each of these three characters appears at least once in each line, and 'W’s are always on the left of 'S’s.

A test case of N = 0 and M = 0 indicates the end of input, and should not be processed.

Output

For each test case, you should output one line containing one integer, which is the least number of nodes in the separator after the improvement.

Sample Input
6 6
WWSBBB
WSSBBB
WSBBBB
WSBBBB
WSSSBB
WWWSBB
0 0
Sample Output
7

题意: 给出一张字母构成的图S代表初始路径,每个点都有一个权值,权值大小时从0开始一直到所有的格子的数目减1。现要求一条路径使得路径和最小,且S最少。(一开始想到的时A * 搜索,后来因为poj的测评机用的c++的版本太古老,很多的stl里面的结构都不支持,懒得把写好的那些代码修改了,然后从网上看了看题解,写了这篇博客)

题解: 不难发现我们每做一次调整(将格子左移一下)会使得整体减少2。在这里插入图片描述
由上图可以看出,粉色的线所占的格子时7格,而黑线占的格子时9格,很容易找出每往左移一次就会减少两个S所占的格子。

使用两次bfs来探索,第一次探索把S左边的为B的格子都设置为S,然后第二次探索即可找出结果。

c++ AC代码

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
 
const int MOVE[3][2] = {
    {0, 1},//right
    {1, 0},//down
    {0, -1}//left
};

int M, N;
char map[200][201];
bool vis[200][200];
bool inputMap()
{
    scanf("%d%d", &M, &N);
    if(M == 0) return false;
    while(getchar() != '\n');
    for(int i = 0; i < M; ++i) gets(map[i]);
    return true;
}


bool isOutOfBounds(int r, int c)  // 判断该坐标是否超出范围
{
    return r < 0 || r >= M || c < 0 || c >= N;
}
struct Point{
    int r, c;
    Point(int rr, int cc):r(rr), c(cc){}
};

int bfs()
{
    queue<Point> q;
//step 0: initialize
    for(int i = 0; i < M; ++i) memset(vis[i], false, N);
//step 1: find start at up, right to left
    for(int c = N - 2; c > 0; --c){
        if(map[0][c] == 'S'){
            q.push(Point(0, c));
            vis[0][c] = true;
        }
    }
//step 2: bfs to find way to bottom
    int level = 1;
    while(!q.empty()){
        for(int n = q.size(); n > 0; --n){
            Point now = q.front();
            q.pop();
            for(int i = 0; i < 3; ++i){
                int r = now.r + MOVE[i][0], c = now.c + MOVE[i][1];
                if(isOutOfBounds(r, c) || map[r][c] != 'S' || vis[r][c]) continue;
                q.push(Point(r, c));
                vis[r][c] = true;
            }
            if(!isOutOfBounds(now.r, now.c+1) && map[now.r][now.c+1] == 'B')
                map[now.r][now.c+1] = 'S';
            if(now.r + 1 == M) return level;
        }
        ++level;
    }
    return -1;
}
 
int main()
{
    while(inputMap()){
        bfs();
        printf("%d\n", bfs());
    }
    return 0;
}

过程图片展示

  • 初始状态(灰色格子表示走过的路径)

  • 在这里插入图片描述

  • 第一次搜索之后
    -在这里插入图片描述
    第一次填充后的状态,黄色部分也被填充上了S。

  • 第二次搜索开始:首先将最上面两个绿色的格子放到了队列里面。(此时n值是2)
    在这里插入图片描述

  • 先搜索了数值时33的节点,把33的节点从队列中删掉了,同时将27加入到了节点中。在这里插入图片描述
    (蓝色代表不在队列中了,把33的节点出队之后n便减1,这时n的值变成了1,接着又遍历32的节点,然后把与32相邻且没用访问过的节点加入到了队列中。在这里插入图片描述
    这时n已经减为0了,第一次循环完毕,level加1,即结果加了一个节点。

  • 这时队列里面有2个节点,数值为26和27的节点,搜索27,发现与它相邻的节点没有符合条件要求的,所有我们直接跳过。搜索26,我们把25和20又加进了队列中,这时这一次的遍历又完毕了,level又加1(此时level已经达到3)。
    在这里插入图片描述

  • 队列的大小还是2,搜索25,把19进队,搜索20把14进队,level又加1。
    在这里插入图片描述

  • 搜索19把13进队,搜索14,把8进队。完毕,level加1(level此时为5)。
    在这里插入图片描述

  • 搜索13,把7入队,搜索8,把9入队,leve加1(leve==6)。
    在这里插入图片描述

  • 接着搜索7,发现没用符合要求的与它相邻的节点,跳过,继续搜索9把3和10入队。level加1(level==7)。
    在这里插入图片描述

  • 这是最后一步,搜索10,把4入队,搜索3,把4入队,因为数值为3的节点的行下标是5,也就是说它已经是到达终点了,所以直接返回level,没有经过最后的level++;语句。

输出的最终结果也就是答案所求(从终点出发倒过来推父节点,即最短路径)。

代码参考自:https://blog.csdn.net/uuuououlcz/article/details/31373961

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值