题解 洛谷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); } } }
但是结果并不理想,超时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;//完美结束 }
效率
那么,这样的代码能跑多快呢?
差距显而易见
-
但是结果并不理想,超时5个点。
于是,我们考只好虑剪枝:
- 因为我们现在是无脑爆搜,所以有很多路径最终是走不到终点的。
- 假设现在我们走到了(i,j),已经用了S个时间单位,目标点是(p,q),要求在T时走到终点。
- 那么,我们至少需要再花费abs(p-i)+abs(q-j)的时间走到终点。
- 策略已经浮出水面:如果S+abs(p-i)+abs(q-j)>T,那么就不用继续搜索了。
可是,这样能过吗?
代码及解释
经过本蒟蒻(菜鸟)的亲身实践,以上剪枝足够了。
如果有不懂的同学可以继续看代码中的注释哦!
不要妄图追上西坠的太阳,而是要在黎明前就等着它!