题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1175
题目意思:给一个n*m的图,图中都是数字,0是空的地方,然后有q次询问,问(x1,y1)和(x2,y2)两点是否可以通过两次及以下的转弯到达,这题可以用bfs+优先队列写,也可以用dfs写,我用的是dfs
代码中注释我觉得比较好理解的,这里就不多写了。
#include<iostream> #include<cstring> #include<algorithm> using namespace std; int map[1005][1005]; int v[1005][1005]; int ans=0; int d[4][2]={1,0,-1,0,0,-1,0,1}; int n,m,x1,x2,y1,y2; void dfs(int x,int y,int wan,int t)//wan表示转弯的方向,t表示转弯的次数 { if(ans) return ; if(x<1||x>n||y<1||y>m) return ; if(v[x][y]) return ; if(t>2||(t==2&&(x-x2)&&(y-y2)))//剪枝,转过第二次弯后,如果终点不在同一行或同一列那么肯定要再转弯 return ; if(x==x2&&y==y2)//到终点了 { ans=1; return ; } if(map[x][y]!=0)//0才是可以走的路 { if(x==x1&&y==y1); else return ; } for(int i=0;i<4;i++) { v[x][y]=1; if(wan!=i)//转弯的状态用i来记录 { if(x==x1&&y==y1)//由于起点的方向不一定,所以起点的转弯数不能变 dfs(x+d[i][0],y+d[i][1],i,t); else dfs(x+d[i][0],y+d[i][1],i,t+1); } else//没有转弯 dfs(x+d[i][0],y+d[i][1],wan,t); v[x][y]=0;//别玩了把标记还原; } //cout<<x<<" "<<y<<endl; } int main() { while(cin>>n>>m ) { if(n==0&&m==0) break; memset(map,0,sizeof(map)); memset(v,0,sizeof(v)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>map[i][j]; } int q; cin>>q; while(q--) { ans=0; cin>>x1>>y1>>x2>>y2; if(map[x1][y1]!=map[x2][y2]||map[x1][y1]==0)//这里可以把一些 不可能的状态去掉,仔细想想不难理解。 { cout<<"NO"<<endl; continue; } dfs(x1,y1,0,0); if(ans) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } }
下面给出我找到的和我想的一些样例
5 7
0 0 1 0 2 3 4
1 2 0 0 4 3 5
6 5 0 0 0 0 7
0 3 3 5 0 6 7
3 3 3 2 0 0 1
10
1 7 2 5
2 7 4 4
1 3 2 1
1 3 5 7
1 6 2 6
1 1 1 2
3 2 4 4
2 2 1 5
4 3 1 6
2 2 2 2
N
N
Y
N
Y
N
Y
Y
N
Y
3 4
5 0 1 0
0 0 0 0
1 4 0 5
2
3 4 1 1
1 1 3 4
3 4
1 1 0 5
0 0 0 0
5 0 1 0
2
3 1 1 4
1 4 3 1
3 4
5 0 1 0
5 0 0 0
1 4 0 5
4
3 4 1 1
1 1 3 4
2 1 3 4
3 4 2 1
0 0
Y
Y
Y
Y
N
N
Y