第六届湖南省省赛 Biggest Number(DFS+BFS,巧妙剪枝)

版权声明:转就转吧~~记得声明噢~~ https://blog.csdn.net/Soul_97/article/details/82622265

1738: Biggest Number

描述

题目描述:

 

You have a maze with obstacles and non-zero digits in it:

You can start from any square, walk in the maze, and finally stop at some square. Each step, you may only walk into one of the four neighbouring squares (up, down, left, right) and you cannot walk into obstacles or walk into a square more than once. When you finish, you can get a number by writing down the digits you encounter in the same order as you meet them. For example, you can get numbers 9784, 4832145 etc. The biggest number you can get is 791452384, shown in the picture above.

 

Your task is to find the biggest number you can get.

 

Input

There will be at most 25 test cases. Each test begins with two integers R and C (2<=R,C<=15, R*C<=30), the number of rows and columns of the maze. The next R rows represent the maze. Each line contains exactly C characters (without leading or trailing spaces), each of them will be either '#' or one of the nine non-zero digits. There will be at least one non-obstacle squares (i.e. squares with a non-zero digit in it) in the maze. The input is terminated by a test case with R=C=0, you should not process it.

 

Output

For each test case, print the biggest number you can find, on a single line.

输入:

输出:

样例输入

3 7
##9784#
##123##
##45###
0 0

样例输出

791452384

复杂的思路和剪枝。。

原谅自己做不出来了。。

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int MAX_NUM = 30 + 5;

// 位置节点,用于广搜中的队列
struct node {
    int x, y;
} queue[1000];
// 行、列
int n, m;
// 当前最大递归深度
int Max;
// 标记当前深搜深度与当前最优解该位置的关系
// 0:相等 1:大于 -1:小于
int flag;
// 数字总数
int total;
// 图
char map[MAX_NUM][MAX_NUM];
// 最优值和当前值
char ans[MAX_NUM], stack[MAX_NUM];
// 方向
int dir[4][2] = {{-1, 0},
                 {0,  -1},
                 {0,  1},
                 {1,  0}};

bool ok(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m;
}

// 广搜找到(x,y)点开始的,剩下可访问数字的数量
int bfs(int x, int y) {
    node t;
    char g[20][20];
    for (int i = 0; i < n; i++) {
        strcpy(g[i], map[i]);
    }
    int head, tail;
    head = tail = 0;
    t.x = x, t.y = y;
    queue[tail++] = t;
    while (head < tail) {
        x = queue[head].x;
        y = queue[head++].y;
        for (int i = 0; i < 4; i++) {
            int xx = x + dir[i][0];
            int yy = y + dir[i][1];
            if (!ok(xx, yy) || g[xx][yy] == '#') {
                continue;
            }
            g[xx][yy] = '#';
            t.x = xx;
            t.y = yy;
            queue[tail++] = t;
        }
    }
    return head;
}

void dfs(int x, int y, int cnt) {
    // 深度更深或者深度相等但是当前值更大
    if (Max < cnt || (Max == cnt && flag == 1)) {
        // 0表示字符串结尾
        stack[cnt] = 0;
        // 更新当前值为当前最优解
        strcpy(ans, stack);
        // 当前最大递归深度为当前深度
        Max = cnt;
        // 位置关系更新为等于
        flag = 0;
    }
    // 剩下可访问数字的数量
    int res = bfs(x, y);
    // 最优性剪枝:剩下可访问数字数量+当前深度小于当前最优深度
    // 或者以上相同但是当前值小一些
    if (res + cnt - 1 < Max || (res + cnt - 1 == Max && flag == -1)) {
        return;
    }
    for (int i = 0; i < 4; i++) {
        int xx = x + dir[i][0];
        int yy = y + dir[i][1];
        // 可行性剪枝:出界或者不为数字
        if (!ok(xx, yy) || map[xx][yy] == '#') {
            continue;
        }
        // 最优性剪枝:当前深搜深度或值不大于
        // 且当前最优的第cnt位大于扩展节点值
        // 且已经找到了一条覆盖了所有数字的路径
        if (flag != 1 && ans[cnt] > map[xx][yy] && total == Max) {
            continue;
        }

        // 赋值并标记
        stack[cnt] = map[xx][yy];
        map[xx][yy] = '#';
        // 更新flag表示的位置关系
        if (flag == 0) {
            if (cnt >= Max) {
                flag = 1;
            } else if (ans[cnt] == stack[cnt]) {
                flag = 0;
            } else if (ans[cnt] < stack[cnt]) {
                flag = 1;
            } else {
                flag = -1;
            }
            // 深搜
            dfs(xx, yy, cnt + 1);
            // 回溯
            flag = 0;
        } else {
            // 深搜
            dfs(xx, yy, cnt + 1);
        }
        // 回溯
        map[xx][yy] = stack[cnt];
    }
}

int main() {
    while (scanf("%d%d", &n, &m) && n + m) {
        // 输入并获取数字总数
        total = 0;
        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
            for (int j = 0; j < m; j++) {
                if (map[i][j] != '#') {
                    total++;
                }
            }
        }
        // 初始化
        Max = 1;
        memset(ans, 0, sizeof(ans));
        // 遍历深搜
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 可行性剪枝:必须是数字
                if (map[i][j] == '#') {
                    continue;
                }
                // 最优性剪枝:搜索到的路径已覆盖所有数字
                // 如果这时的最优值最高位>当前深搜的第一位,那么就可以剪枝
                if (Max == total && ans[0] > map[i][j]) {
                    continue;
                }

                stack[0] = map[i][j];
                // 标记
                map[i][j] = '#';

                // 获取当前深搜首位与当前最优解首位的关系
                if (ans[0] == stack[0]) {
                    flag = 0;
                } else if (ans[0] < stack[0]) {
                    flag = 1;
                } else {
                    flag = -1;
                }
                // 深搜
                dfs(i, j, 1);
                // 还原
                map[i][j] = stack[0];
            }
        }
        printf("%s\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Soul_97/article/details/82622265