题目大意:

从一个点走到另一个点,必须要在限制时间内走完,并且不能撞到障碍物上,问有多少种方法。


此题有两种算法可以做,我将都为大家介绍。(其实两种思路都差不多,只是算法不同而已,一个是宽(广)搜,一个是动规)

第一种方法BFS:

递归每一个点,如果这个点还可以通往其他没有障碍物的话,就继续递归下去,否则返回。如果到达目的地就直接Return。

代码如下


#include <bits/stdc++.h>//万能头文件
using namespace std;//常规
int jsq,cnt,k;//定义变量
char e[255][255];//字符数组
int n,m,st1,st2,de1,de2;//起点与终点
int xx[5]={0,-1,0,1};
int yy[5]={-1,0,1,0};//打表
void zou(int x,int y,int z)//递归函数
{
    if(z==k)//如果体力已尽或已到达目的地就Return
    {
        if(x==de1&&y==de2)
        {
            jsq++; //但如果到达方法就+1
        }
        return ;//返回
    }
    for(int i=0;i<4;i++)//枚举
    {
        int dx=x+xx[i],dy=y+yy[i];
        if(dx>=1&&dy>=1&&dx<=n&&dy<=m&&e[dx][dy]=='.')//如果可以继续递归就继续下去,如果不能就枚举下一个点
        {
            zou(dx,dy,z+1);//继续下去
        }
    }
}
int main()//主函数
{
    cin>>n>>m>>k;//输入长宽以及体力
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>e[i][j];//输入是否可走
        }
    }
    cin>>st1>>st2>>de1>>de2;//输入起点终点
    zou(st1,st2,0);//递归
    cout<<jsq;//输出方法总数
    return 0;//结束
}

但是我们发现以上代码只能得40分,若开O2优化可得50分(阴招),怎么优化呢?

咱们做一个假设,如果体力值还剩五个单位,而路程还剩十五个单位,那么肯定走不了,所以我们只要加一个判断就可以了。

AC Code:


#include <bits/stdc++.h>//万能头文件
using namespace std;//常规
int jsq,cnt,k;//定义变量
char e[255][255];//字符数组
int n,m,st1,st2,de1,de2;//起点与终点
int xx[5]={0,-1,0,1};
int yy[5]={-1,0,1,0};//打表
void zou(int x,int y,int z)//递归函数
{
    if(z==k)//如果体力已尽或已到达目的地就Return
    {
        if(x==de1&&y==de2)
        {
            jsq++; //但如果到达方法就+1
        }
        return ;//返回
    }
    if(z+abs(x-de1)+abs(y-de2)>k)//如果路程比体力多,那么肯定不行,直接Return
    return ;
    for(int i=0;i<4;i++)//枚举
    {
        int dx=x+xx[i],dy=y+yy[i];
        if(dx>=1&&dy>=1&&dx<=n&&dy<=m&&e[dx][dy]=='.')//如果可以继续递归就继续下去,如果不能就枚举下一个点
        {
            zou(dx,dy,z+1);//继续下去
        }
    }
}
int main()//主函数
{
    cin>>n>>m>>k;//输入长宽以及体力
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>e[i][j];//输入是否可走
        }
    }
    cin>>st1>>st2>>de1>>de2;//输入起点终点
    zou(st1,st2,0);//递归
    cout<<jsq;//输出方法总数
    return 0;//结束
}

此题还有一种做法就是直接DP,思路和前面的BFS一样(如果这个点还可以通往其他没有障碍物的话就把值存储下来,并判断可否到达终点),只是这个是直接枚举,而上一个是递归,这样还可以节省时间(BFS花了833毫秒,而DP只用了32毫秒),并且也十分简单,用一个数组存储答案,一个数组进行判断,最后直接输出终点存储的值即可。

Another AC Code


#include <bits/stdc++.h>//万能头文件
using namespace std;//常规
int xx[5]={0,0,-1,0,1};
int yy[5]={0,-1,0,1,0};//照样打表
int main()
{
    int n,m,k;
    cin>>n>>m>>k;//输入长宽以及体力
    int a[n+5][m+5],b[n+5][m+5];//定义两个数组,以用来存储,一个用来判断
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));//清空两个数组
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            char c;
            cin>>c;//可以节约空间
            if(c=='*')//转换一下
            b[i][j]=a[i][j]=-1;//输入并存储是否可走
        }
    }
    int st1,st2,de1,de2;
    cin>>st1>>st2>>de1>>de2;//输入起点以及终点
    b[st1][st2]=a[st1][st2]=1;//起点值为1
    for(int i=1;i<=k;i++)//枚举步数,如果步数没了就可以自动跳出
    {
        for(int j=1;j<=n;j++)
        {
            for(int p=1;p<=m;p++)//枚举每个点的横竖坐标
            {
                if(a[j][p]!=-1)//如果可以走就枚举那个点附近的点
                {
                    b[j][p]=0;//复制成零(方便计算)
                    for(int q=1;q<=4;q++)//枚举方向
                    {
                        int dx=j+xx[q],dy=p+yy[q];//把每个方向的坐标都算出来
                        if(a[dx][dy]!=-1)//如果可以就存储答案
                        b[j][p]+=a[dx][dy];//存储答案
                    }
                }
            }
        }
        for(int s=1;s<=n;s++)
        {
            for(int t=1;t<=m;t++)
            {
                a[s][t]=b[s][t];//把B的值赋值给A,并继续计算
            }
        }
    }
    cout<<a[de1][de2];//直接输出终点的方案数(重点所存储的值
    return 0;//结束
 }

ps:写了一个晚上,求过。。。

珍惜账号,远离抄袭!