Description
Input
Output
Sample Input
2 5 5 ...** *.**. ..... ..... *.... 1 1 1 1 3 5 5 ...** *.**. ..... ..... *.... 2 1 1 1 3
Sample Output
no yes
这个题卡在不知道怎么判是否转弯,不过看了大神的解题就懂了,程序里的(dir!=-1 && i!=dir)就是用来判断是否转弯了。
本题我是用的dfs,找到终点时并不晕就返回真,程序并没有遍历整个图。并且在走重时会根据在重点的转弯值turn判断以选优,
这在程序中已实现,并作为剪枝,注意本题剪枝很重要,不然会超时的!!
下面来解释一下bfs()中if()剪枝中为什么相等的情况不能剪掉(先看代码去):
很明显,如果k=1的话,那么途中红线是不符合题意的,我们来谈论最中心的那个点(下面我们叫它中心点):
走红线时,在中心点的turn值是1,当然要去终点的到还需要再转一次,就不符合题意,一次放弃这条路线,但是中心点的turn就此存在了,并且是1.
当再走蓝线时,走到该点时turn值也是1,此时人没晕,一直走是可以走到终点的,所以这种情况是应该输出“yes”的。
但如果你把相等的情况剪掉了,那么就是相当于把蓝线这种可能给否定了,那自然就错了。
造成这种情况的原因其实很简单,因为不同路线的到达相同的点时,因为来的时候方向不同,要是再朝相同的方向(即终点的方向)走时,有的需要转一次;有的则不需要,接着原来的方向走就行。
代码如下:
#include <stdio.h> #include <string.h> #include <math.h> #define Max 999999 #include <algorithm> using namespace std; struct point { int x,y; }s[20000]; char map[110][110]; int turn[110][110]; int n,m,x2,y2,ok,k; int dx[4]={1,-1,0,0}; int dy[4]={0,0,1,-1}; void dfs(int x,int y,int dir) { int i,xx,yy; if(x==x2 && y==y2 && turn[x][y]<=k) //成功的时候返回 { ok=1; return ; } if(turn[x][y]>k) //大于k时已晕,不行 return ; if(x!=x2 && y!=y2 && turn[x][y]==k) //如果(x,y)和终点(x2,y2),既不在同一行也不在同一列,那么要想到终点至少需要转一次,但现在已经转够k次了,故不行 return ; for(i=0;i<4;i++) { xx=x+dx[i]; yy=y+dy[i]; if(xx<=0 || yy<=0 || xx>m || yy>n || map[xx][yy]=='*') continue; //注意!!!下面这行中的turn[xx][yy]是表示(xx,yy)已经由别的路线走过了,并记录了turn[xx][yy],现在需要比较这次走到(xx,yy)和由别的路线走到 //(xx,yy)时,两个的turn值,如果上次的比这次的小,说明这次不行,故要continue; if(turn[xx][yy]<turn[x][y]) //这里相等的情况不能剪掉,原因开头已解释 continue; //下面这条if和上面的差不多,目的是:如果从(x,y)走一步到(xx,yy)需要转一次话,并且转过之后turn[x][y]+1依然比turn[xx][yy]大的话,也不符合 if(dir!=-1 && i!=dir && turn[xx][yy]<turn[x][y]+1) continue; //这两个if语句剪枝很重要,没有的话就超时 if(dir!=-1 && i!=dir) turn[xx][yy]=turn[x][y]+1; else turn[xx][yy]=turn[x][y]; map[xx][yy]='*'; //如果这里能走,就把这里变成不能走,然后再从这里开始递归,其实就是起到vis[][] 的作用,会用vis的话就不用追究了 dfs(xx,yy,i); map[xx][yy]='.'; //这里再变成'.',是为了不影响其他的递归过程,因为其他路线可能还要从这里过 if(ok) return ; } } int main() { int i,j,t,x1,y1; scanf("%d",&t); while(t--) { scanf("%d%d",&m,&n); for(i=1;i<=m;i++) for(j=1;j<=n;j++) scanf(" %c",&map[i][j]); scanf("%d%d%d%d%d",&k,&y1,&x1,&y2,&x2); //注意,这里是先接y,再接x,我被坑了好长时间 memset(turn,Max,sizeof(turn)); //因为在dfs()中剪枝要去最小的转弯次数,所以turn要初始化成最大 ok=0; turn[x1][y1]=0; dfs(x1,y1,-1); if(ok) printf("yes\n"); else printf("no\n"); } return 0; }