Biggest Number(刘汝佳,搜索+剪枝)

本文介绍了一道关于在迷宫中寻找由非零数字组成的最大数的问题。通过使用搜索算法结合剪枝技巧来提高效率,避免了不必要的遍历路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Biggest Number(刘汝佳,搜索+剪枝)

时间限制: 1 Sec   内存限制: 128 MB
提交: 64   解决: 15
[ 提交][ 状态][ 讨论版]

题目描述

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.

输入

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.

输出

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

样例输入

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

样例输出

791452384

提示

这道题是到搜索的好题,一开始我自己用DFS做,直接超时了,后来百度了一下,要结合bfs进行剪枝才可以。

代码如下

参考了该大神的源码:http://blog.youkuaiyun.com/andring/article/details/7376129

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char map[30][30];
int visti2[30][30];
int r,c;
int flag;
int maxn,total;
int dir[4][2]= {{1,0},{-1,0},{0,-1},{0,1}};
char ans[100],stack1[100];
int max;
struct xy {
    int x,y;
};
xy que[1000];
bool yes(int x,int y) {
    return x>=0&&x<r&&y>=0&&y<c; //该点是否在地图中,是就返回true
}
int bfs(int x,int y) {
    int f=0;
    int re=0;
    char visti[30][30];
    memcpy(visti,map,sizeof(map));
    que[f].x=x;
    que[f].y=y;
    while(f<=re) {
        int x1=que[f].x;
        int y1=que[f].y;
        for(int i=0; i<4; i++) {
            int newx=x1+dir[i][0];
            int newy=y1+dir[i][1];
            if(newx<r && newx>=0 && newy<c && newy>=0)
                if(visti[newx][newy]!='#') {
                    visti[newx][newy]='#';
                    ++re;
                    que[re].x=newx;
                    que[re].y=newy;
                }
        }
        f++;
    }
    return f;
}

void dfs(int x,int y,int cnt) { //当前检索点的坐标情况,当前检索到的数的长度
    if(maxn<cnt||(maxn==cnt&&flag==1)) //当前检索到的数的长度大于当前检索到的最大的数的总长度“或”长度相等但是当前值首数字比较大
        //当前检索到的值必定大于当前检索到的“最大值”【强剪枝2】
    {
        stack1[cnt]=0; //字符串结束标志【别忘了,字符数组没有结束标志会输出错误的】
        strcpy(ans,stack1); //将当前值赋给”最大值“
        maxn=cnt; //改变最大值的长度
        flag=0; //大小不确定
    }
    int res=bfs(x,y); //该点后面还能搜索到res个有效数字
    if(res+cnt-1<maxn||(res+cnt-1==maxn&&flag==-1))return; //若该点参与的检索中的有效数字的最大长度小于当前检索到的数字中的最大值的长度
    //长度相等,但是该次检索的数字要小【这个数肯定小于当前检索到的最大值】直接结束搜索【强剪枝3】
    for(int i=0; i<4; i++) { //当前的搜索得到的数肯定会大于当前检索到的最大值,【搜索继续】
        int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(!yes(xx,yy)||map[xx][yy]=='#')continue; //该点不在地图中,或该点不可处理【不作处理】【常规剪枝】
        if(flag!=1&&ans[cnt]>map[xx][yy]&&total==maxn)continue; //当前检索的值不可能大于当前检索到的最大值【强剪枝4】
        stack1[cnt]=map[xx][yy]; //检索到的数字可用,加入到临时【当前检索值的情况】中
        map[xx][yy]='#'; //记得标记哦,检索过的就不要再检索了
        if(flag==0) { //【】【】大小不确定
            if(cnt>=maxn)flag=1; //长度,当前检索到的比较大
            else if(ans[cnt]==stack1[cnt])flag=0; //长度想相同就比首字母 【大小不确定】
            else if(ans[cnt]<stack1[cnt])flag=1; //当前检索到的i较大
            else flag=-1; //当前检索到的比较小
            dfs(xx,yy,cnt+1); //长度加1
            flag=0;//【大小不确定】
        } else dfs(xx,yy,cnt+1); //若大小确定,继续检索
        map[xx][yy]=stack1[cnt]; //搜索归来,抹去标记
    }
}
int main() {
    while(scanf("%d%d",&r,&c),r!=0&&c!=0) {
        int i,j;
        total=0;
        for(i=0; i<r; i++) {
            scanf("%s",map[i]);
            for(j=0; j<c; j++)
                if(map[i][j]!='#') total++;
        }
        maxn=1;
        memset(ans,0,sizeof(ans));
        for(i=0; i<r; i++){
            for(j=0; j<c; j++) {
                if(map[i][j]=='#') continue;
                if(maxn==total && ans[0]>map[i][j]) continue;
                stack1[0]=map[i][j];
                map[i][j]='#';
                if(stack1[0]==ans[0]) flag=0;
                else if(stack1[0]>ans[0]) flag=1;
                else  flag=-1;
                dfs(i,j,1);
                map[i][j]=stack1[0];
            }
            }
        printf("%s\n",ans);


    }
    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值