2930 地图

dp[1][2][3][4]
//位置
//方向
//可转向次数

 


 

//本题需要结合dfs+记忆化搜索+动态规划来解题
//对于当前坐标(i,j),其下一步有两个转移方向,分别是向下(i+1,j)和向右(i,j+1)
//故从(i,j)到达(N,M)的方案数等于从(i+1,j)到(N,M)和从(i,j+1)到(N,M)的方案数之和
//由于最多转向K次,每次转移状态时需要记录当前方向和下一步转移的方向,以及已经转向的次数
//且每次回溯时都要恢复转向次数k,时间复杂度很高,因此使用记忆化数组保存中间结果 
//故使用四维记忆化数组进行记录,每转移一次都要传入当前坐标、当前方向、已转移次数等参量 
#include <bits/stdc++.h>
using namespace std;
char matrix[110][110];//迷宫矩阵 
int N,M,K;
int dp[105][105][2][7];//记忆化数组 
//dp[i][j][0][k]表示从(i,j)开始,方向向右,共改变了k次方向,能到达终点的方案数 
//dp[i][j][1][k]表示从(i,j)开始,方向向下,共改变了k次方向,能到达终点的方案数 
 
bool ok(int i,int j)//判断是否是可通行的点 
{
    //if(i>N||j>M)return false;
    //这里可以优化,只要不是点就返回false
    if(matrix[i][j]=='.')return true;
    else return false;    
} 
int dfs(int row,int col,int tag,int k)//从(row,col)开始进行dfs,当前方向为tag,总共改变了k次方向
{
    int cnt=0;//记录总方案数 
    if(!ok(row,col))return 0;//该点不可通行,直接返回0 
    if(row==N&&col==M)return 1;//到达终点,直接返回1,表示这是一种方案最终条件
    if(dp[row][col][tag][k])return dp[row][col][tag][k];
    //已经搜索过该点,直接返回记忆化数组的值 
    //一开始是的值都是0,所以不会进行
    if(k<K)//转向的次数没有超过K次 
    {//看来碰到石头并不是碰到石头再转向
        cnt=cnt+dfs(row+1,col,1,tag==1?k:k+1);//向下 
        //这一步是向下走,tag为1表示原来向下,所以不转向,所以k不变化
        //反之若tag=0说明表示往右走则k++
        cnt=cnt+dfs(row,col+1,0,tag==0?k:k+1);//向右 
    }
    else if(k==K)//转向次数已经达到K次 
    {
        if(tag==0)//原来向右 
        {
            cnt=cnt+dfs(row,col+1,tag,k);//继续向右    
        } 
        else if(tag==1)//原来向下 
        {
            cnt=cnt+dfs(row+1,col,tag,k);//继续向下 
        }
    }
    dp[row][col][tag][k]=cnt;//当前值为从当前点出发的所有值
    //记忆化,将从(row,col)到(N,M)的总方案数保存起来 
    //最后这个cnt直接将结果保存下来了
    return cnt;//返回从(row,col)到(N,M)的方案数 
}
int main()
{
    int ans=0;
    cin>>N>>M>>K;
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=N;i++)
    {
        for(int j=1;j<=M;j++)
        {
            cin>>matrix[i][j];    
        }    
    }    //初始化数组并且   
    //此处要注意一点,起点(1,1)处是没有当前方向的,需要前进一步才有方向 
    if(ok(1,2))ans=ans+dfs(1,2,0,0);//从(1,2)开始 
    if(ok(2,1))ans=ans+dfs(2,1,1,0);//从(2,1)开始 
    cout<<ans<<endl;
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值