HDU5335 Walk Out(dfs+递推)

本文介绍了一种求解字典序最小路径的问题解决方法,通过寻找最短且值最小的路径来解决问题,并使用DFS进行搜索,适用于01矩阵。

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

题意:大致意思是给一个n*m的01矩阵,起点为左上方(1,1),终点为右下方(n,m),求从左上方到右下方字典序自小的路径,如果路径都为0,则输出0。


分析:首先字典序最小,先要满足路径最短,再满足路径的值最小,路径最短的毫无疑问是越靠下或者越靠右,而且如果路径的前面为0,则可以认为是以第一个非0的点的为起点。因此这题可以转化为:先找出以起点为中心的连续为零的集合,再在其中找出x+y最大的一些点为起点,(当然如果s[1][1]==1,起点就是左上方),然后以这些点不断往下往右寻找下一排的最小值,然后以下一排的最小值的为起点的所有点再往下递推,直到终点。(这里每一排的递推的起点和终点推理可以画图推出),也就是用dfs搜四个方向,递推两个方向向下和向右。

图中的点值为x+y,当tot=2时,下一排的x的起点为tot-m>=tot-m?1为1,终点为i-n<=1?i-1:n,为1,后面的斜排同理

234
345
456
 

注意:之前博客提到的,由于这里用到dfs,而且栈最大要开4000000,(但是用bfs写就不需要了)所以在hdu交的话要手动扩栈,而且要用c++交。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include<vector>
#pragma comment(linker,"/STACK:1024000000,1024000000") //手动扩栈
using namespace std;
const int maxn = 1e3+5;
int n,m;
int tot;
char s[maxn][maxn];
bool vis[maxn][maxn];
void dfs(int x,int y)
{
    if(vis[x][y]||s[x][y]-'0') return;//边界条件
    vis[x][y]=1;                      //能走到的点标记
    if(x+y>tot) tot=x+y; //标记最靠下的斜线的x+y
    if(x<n) dfs(x+1,y);  //向下
    if(x>1) dfs(x-1,y);  //向上
    if(y<m) dfs(x,y+1);  //向右
    if(y>1) dfs(x,y-1);  //向左
}
void solve()
{
    if(s[1][1]=='1'){
        printf("1");
        vis[1][1]=1;
    }
    else if(s[1][1]=='0'&&tot==m+n){
        printf("0");
    }
    for(int i=tot;i<n+m;i++){
        int nw = 1;
        for(int j=(i-m>=1?i-m:1);j<=(i-n<=1?i-1:n);j++){//斜线的初始点到终点
            int nx = j;
            int ny = i-j;
            if(vis[nx][ny]){//由上一排得到能走的点
                if(nx<n) nw = min(s[nx+1][ny]-'0',nw);//右边
                if(ny<m) nw = min(s[nx][ny+1]-'0',nw);//下边
            }
        }
        for(int j=(i-m>=1?i-m:1);j<=(i-n<=1?i-1:n);j++){
            int nx = j;
            int ny = i-j;
            if(vis[nx][ny]){
                if(nx < n && s[nx+1][ny]-'0'==nw) vis[nx+1][ny]=1;//标记下一排能走的点
                if(ny < m && s[nx][ny+1]-'0'==nw) vis[nx][ny+1]=1;
            }
        }
        printf("%d",nw);
    }
    printf("\n");
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof(vis));
        tot=2;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
        dfs(1,1);
        solve();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值