题解 洛谷P1535 【[USACO08MAR]Cow Travelling S】

这道题可不是个水题嘛!

初始思路

这道题目是很明显的搜索,我推荐使用深度优先搜索,简称DFS。

终止条件:如果时间到了,那么结束搜索。

搜索时使用的参数:当前横、纵坐标,以及当前时间。

扩散:每一次向四周搜索,不能跑出地图,而且不能撞墙。

剪枝:由于数据较小,可以不剪枝(假的,后面会发现问题)。

剪枝策略

根据上面的思路,我们很容易敲出代码。

inline void Dfs(int Nx,int Ny,int Step)
{
    if(Step==Time)
    {
        if(Ex==Nx&&Ey==Ny)
        {
            Ans++;
        }
        return;
    }
    register int i;
    for(i=0;i<4;i++)
    {
        int Nxt_X,Nxt_Y;
        Nxt_X=Nx+Dir[i][0];
        Nxt_Y=Ny+Dir[i][1];
        if(Nxt_X>0&&Nxt_X<=Line&&Nxt_Y>0&&Nxt_Y<=Column&&Map[Nxt_X][Nxt_Y]!='*')
        {
            Dfs(Nxt_X,Nxt_Y,Step+1);
        }
    }
}
View Code

但是结果并不理想,超时5个点。

于是,我们考只好虑剪枝:

因为我们现在是无脑爆搜,所以有很多路径最终是走不到终点的。

假设现在我们走到了(i,j),已经用了S个时间单位,目标点是(p,q),要求在T时走到终点。

那么,我们至少需要再花费abs(p-i)+abs(q-j)的时间走到终点。

策略已经浮出水面:如果S+abs(p-i)+abs(q-j)>T,那么就不用继续搜索了。

可是,这样能过吗?

代码及解释

经过本蒟蒻(菜鸟)的亲身实践,以上剪枝足够了。

如果有不懂的同学可以继续看代码中的注释哦!

#include<bits/stdc++.h>
using namespace std;
int Line,Column,Time;//行数、列数、要求的时间
char Map[101][101];//输进来的地图
int Sx,Sy,Ex,Ey;//初始横纵坐标、目标横纵坐标
int Ans;//答案
int Dir[4][2]={1,0,0,1,-1,0,0,-1};//每次向四周扩散
inline void Dfs(int Nx,int Ny,int Step)
{
    if(Step==Time)//如果时间到了
    {
        if(Ex==Nx&&Ey==Ny)//如果走到了终点
        {
            Ans++;//更新答案
        }
        return;//返回
    }
    if(abs(Ex-Nx)+abs(Ey-Ny)+Step>Time)//剪枝策略
    {
        return;//无解,返回
    }
    register int i;
    for(i=0;i<4;i++)//向四周扩散
    {
        int Nxt_X,Nxt_Y;
        Nxt_X=Nx+Dir[i][0];//下一个点横坐标
        Nxt_Y=Ny+Dir[i][1];//下一个点纵坐标
        if(Nxt_X>0&&Nxt_X<=Line&&Nxt_Y>0&&Nxt_Y<=Column&&Map[Nxt_X][Nxt_Y]!='*')//如果没有跑出地图,并且没撞墙,那么路径合法
        {
            Dfs(Nxt_X,Nxt_Y,Step+1);//继续搜索
        }
    }
}
int main()
{
    register int i,j;
    cin>>Line>>Column>>Time;//输入
    for(i=1;i<=Line;i++)
    {
        for(j=1;j<=Column;j++)
        {
            cin>>Map[i][j];//输入
        }
    }
    cin>>Sx>>Sy>>Ex>>Ey;//输入
    Dfs(Sx,Sy,0);//搜索
    cout<<Ans<<endl;//输出
    return 0;//完美结束
}
View Code

效率

那么,这样的代码能跑多快呢?

没剪枝的代码速度

有剪枝的代码速度

差距显而易见

  • 但是结果并不理想,超时5个点。

于是,我们考只好虑剪枝:

  • 因为我们现在是无脑爆搜,所以有很多路径最终是走不到终点的。
  • 假设现在我们走到了(i,j),已经用了S个时间单位,目标点是(p,q),要求在T时走到终点。
  • 那么,我们至少需要再花费abs(p-i)+abs(q-j)的时间走到终点。
  • 策略已经浮出水面:如果S+abs(p-i)+abs(q-j)>T,那么就不用继续搜索了。

可是,这样能过吗?

代码及解释

经过本蒟蒻(菜鸟)的亲身实践,以上剪枝足够了。

如果有不懂的同学可以继续看代码中的注释哦!

posted @ 2020-08-08 15:03  Bushuai_Tang  阅读(204)  评论(0编辑  收藏  举报