题目:HDU-1026
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1026
题目:
5 6 .XX.1. ..X.2. 2...X. ...XX. XXXXX. 5 6 .XX.1. ..X.2. 2...X. ...XX. XXXXX1 5 6 .XX... ..XX1. 2...X. ...XX. XXXXX.
It takes 13 seconds to reach the target position, let me show you the way. 1s:(0,0)->(1,0) 2s:(1,0)->(1,1) 3s:(1,1)->(2,1) 4s:(2,1)->(2,2) 5s:(2,2)->(2,3) 6s:(2,3)->(1,3) 7s:(1,3)->(1,4) 8s:FIGHT AT (1,4) 9s:FIGHT AT (1,4) 10s:(1,4)->(1,5) 11s:(1,5)->(2,5) 12s:(2,5)->(3,5) 13s:(3,5)->(4,5) FINISH It takes 14 seconds to reach the target position, let me show you the way. 1s:(0,0)->(1,0) 2s:(1,0)->(1,1) 3s:(1,1)->(2,1) 4s:(2,1)->(2,2) 5s:(2,2)->(2,3) 6s:(2,3)->(1,3) 7s:(1,3)->(1,4) 8s:FIGHT AT (1,4) 9s:FIGHT AT (1,4) 10s:(1,4)->(1,5) 11s:(1,5)->(2,5) 12s:(2,5)->(3,5) 13s:(3,5)->(4,5) 14s:FIGHT AT (4,5) FINISH God please help our poor hero. FINISH
感觉有点悲伤,兴冲冲写了半天DFS,终于样例过了交上去一个TLE,然后回来我就看着代码想一定是我没剪枝的原因,我曾经曰过,搜索题最考验人的就是剪枝,没错儿一定是这样,然后就盯着看怎么剪呢,怎么剪呢。。。最后受不了百度题解的我眼泪流下来,竟然是BFS,嗯哼,我是不会承认我做题少才分不出来什么题目应该用什么算法来做的,死不承认。
好吧,看来有必要弄懂一下DFS和BFS解决问题的区别了,之前已经弄得很清楚了,在二叉树里面,DFS就是一颗一颗子树访问包括前序遍历、中序遍历、后序遍历,是一条一条路径来访问,而BFS就是层次遍历。DFS一般借助于递归和回溯基于栈来完成,而BFS则是基于循环和队列来完成,这是两者定义上的区别想必也不用多说,可是在用这两种算法解决不同问题时就需要注意了,现在这里说一些目前的体会,以后做题多了再来补充。
DFS特点是一条路径一条路径寻找解决问题的方法,并且寻找所有的路径,拿走迷宫为例,它会把所以可以走到的路都走一遍,然后告诉你结果,也就是说它考虑到了所有情况并且可以回退,它适用于解决迷宫问题中规定时间的或者是其它问题中必须要回退的问题,而且DFS往往时间复杂度比较高,剪枝非常有必要。但是剪枝不能解决根本问题,如果数据范围比较大DFS必超时无疑。
BFS 特点是一层一层寻找,找过以后绝不回头,用它可以解决迷宫问题中最短路的问题以及其他一些不需要回退的问题,它的特点是时间复杂度很低最差的情况也不过是O(N*M),但是它的空间复杂度相对就高了,两种方法解决的问题类型是不一样的。
而这道题目就是标准的BFS,此外还有一个难点就是如何打印路径。
那怎么想到BFS,为什么要用BFS呢,首先用DFS解决这道问题是完全可行的,前提是不考虑时间,100X100,DFS会把所有路径跑一遍,想想就是一个可怕的数组,除非是超级傻瓜式的数据否则没可能过,好吧我就傻瓜的做了,不提也罢。DFS解决这道问题可以把迷宫起点看成一棵树的根节点,然后上下左右只要可以走的路径当成是子节点,可以看成是以步数为单位推移,从根节点慢慢扩张,见图:第一个样例可以表示为:
这样子就显而易见了,可以利用队列实现了,具体怎么实现看看代码感觉感觉就好了。
另外一点是怎么打印路径,苦思良久,我的解决方法是结点处加一个指针指向父节点,最后从终点一路回溯到起点,呐,就是这样咯。
#include<iostream> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int maxn=105; char map[maxn][maxn]; //地图 int n,m; int mark[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; int mintime,temp; struct T //存储路径的结点 { int a; int b; int time; }; struct P //BFS过程的结点 { int timemap; int prex; //指向父结点 int prey; }; P p[maxn][maxn]; T ans[10005]; T s,k; void bfs(){ queue<T> Q; //定义队列 s.a=0; s.b=0; s.time=0; Q.push(s); p[0][0].timemap=0; while(!Q.empty()){ //当队列非空时 s=Q.front(); Q.pop(); //取队首,出队 for(int i=0;i<4;i++){ //依旧是跑四个方向,用数组来存起来遍历省代码 int x=s.a+mark[i][0]; int y=s.b+mark[i][1]; if(x>=0 && x<n &&y>=0 && y<m){ if(map[x][y]=='.'){ k.a=x; k.b=y; k.time=s.time+1; if(k.time < p[x][y].timemap){ p[x][y].prex=s.a; p[x][y].prey=s.b; p[x][y].timemap=k.time; Q.push(k); } } else if(map[x][y]>='0' && map[x][y]<='9'){ temp=(int)map[x][y]-48; k.a=x; k.b=y; k.time=s.time+temp+1; if(k.time<p[x][y].timemap){ p[x][y].prex=s.a; p[x][y].prey=s.b; p[x][y].timemap=k.time; Q.push(k); } } } } } } void print(int x,int y,int count){ int ttt=p[x][y].timemap-p[p[x][y].prex][p[x][y].prey].timemap; for(int i=0;i<ttt;i++){ ans[count-i].a=x; ans[count-i].b=y; } if(x==0 && y==0 ) return; print(p[x][y].prex,p[x][y].prey,count-ttt); } int main(){ while(cin>>n>>m){ for(int i=0;i<n;i++) for(int j=0;j<m;j++){ cin>>map[i][j]; p[i][j].timemap=1000005; } bfs(); mintime=p[n-1][m-1].timemap; if(mintime!=1000005){ print(n-1,m-1,mintime); cout<<"It takes "<<mintime<<" seconds to reach the target position, let me show you the way."<<endl; for(int i=1;i<=mintime;i++){ if(ans[i].a==ans[i-1].a && ans[i].b== ans[i-1].b){ cout<<i<<"s:FIGHT AT "<<"("<<ans[i].a<<","<<ans[i].b<<")"<<endl; } else cout<<i<<"s:"<<"("<<ans[i-1].a<<","<<ans[i-1].b<<")->"<<"("<<ans[i].a<<","<<ans[i].b<<")"<<endl; } } else cout<<"God please help our poor hero."<<endl; cout<<"FINISH"<<endl; } return 0; }
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn=105; char map[maxn][maxn]; int n,m; int mark[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; struct T { int a=0; int b=0; }; T s[10005]; T ans[10005]; int mintime; void dfs(int x,int y,int time){ if(map[n-1][m-1]=='X'){ if(time<mintime){ for(int i=0;i<=time;i++){ ans[i].a=s[i].a; ans[i].b=s[i].b; } mintime=time; } } for(int j=0;j<4;j++){ if(x+mark[j][0]>=0 && y+mark[j][1]>=0 && x+mark[j][0]<n && x+mark[j][1]<m){ if(map[x+mark[j][0]][y+mark[j][1]]=='.'){ map[x+mark[j][0]][y+mark[j][1]]='X'; s[time].a=x+mark[j][0]; s[time].b=y+mark[j][1]; dfs(x+mark[j][0],y+mark[j][1],time+1); map[x+mark[j][0]][y+mark[j][1]]='.'; } else if(map[x+mark[j][0]][y+mark[j][1]]>='1' && map[x+mark[j][0]][y+mark[j][1]]<='9'){ char tt=map[x+mark[j][0]][y+mark[j][1]]; int temp=(int)map[x+mark[j][0]][y+mark[j][1]]-48; map[x+mark[j][0]][y+mark[j][1]]='X'; for(int i=time;i<=time+temp;i++){ s[i].a=x+mark[j][0]; s[i].b=y+mark[j][1]; } dfs(x-+mark[j][0],y+mark[j][1],time+temp+1); map[x+mark[j][0]][y+mark[j][1]]=tt; } } } return; } int main(){ ans[0].a=0;ans[0].b=0; while(cin>>n>>m){ for(int i=0;i<n;i++) for(int j=0;j<m;j++) cin>>map[i][j]; mintime=1000005; dfs(0,0,1); mintime--; if(mintime!=1000004){ cout<<"It takes "<<mintime<<" seconds to reach the target position, let me show you the way."<<endl; for(int i=1;i<=mintime;i++){ if(ans[i].a==ans[i-1].a && ans[i].b== ans[i-1].b){ cout<<i<<"s:FIGHT AT "<<"("<<ans[i].a<<","<<ans[i].b<<")"<<endl; } else cout<<i<<"s:"<<"("<<ans[i-1].a<<","<<ans[i-1].b<<")->"<<"("<<ans[i].a<<","<<ans[i].b<<")"<<endl; } } else cout<<"God please help our poor hero."<<endl; cout<<"FINISH"<<endl; } return 0; }