HDU1728:逃离迷宫
传送门
题意
给出一个只由'.'与''构成的nm的图,在不多于k次转弯,问是否能让起点到达终点
分析
这道题花了我2h+,一开始写了一个优先队列+BFS+is数组标记,发现有一组数据过不了
2
3 3
..*
...
*.*
1 1 1 3 2
又用队列重写,发现还是过不了,于是看了这篇blog,扫的时候要将同方向直到*的所有未访问点都放入队列,感谢qqspeed
这种有转弯数限制的题目有些难,它不能用优先队列,因为相同转弯数的点相同位置方向不同就有不同的结果,而用队列也要注意读取点的顺序,比较巧妙
trick
1.开始点与终点可重合,QAQ
2.注意点放入队列的顺序
代码
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define R(i,a,b) for(int i=a;i<b;++i)
#define F(i,a,b) for(int i=a;i<=b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
int t,n,m,k,a[111][111],sx,sy,ex,ey;
int dir[4][2]={0,1,0,-1,-1,0,1,0};
int flag;
bool vis[111][111];
char s[111];
struct node
{
int x,y,turn;
}tmp,p;
bool check(int x,int y)
{
if(x<1||y<1||x>n||y>m||a[x][y]==0) return 0;return 1;
}
queue<node>pq;
void bfs()
{
//printf("1.x=%d y=%d cnt=%d pre=%d\n",x,y,cnt,pre);
//if(cnt==k&&(x-x2)&&(y-y2)) return ;
//printf("(cnt==2&&(x-x2)&&(y-y2))=%d\n",(cnt==2&&(x-x2)&&(y-y2)));
//if(cnt==2&&(x-x2)&&(y-y2)) return ;
//if(x2==x&&y2==y) { flag=1;return ; }
//printf("a[%d][%d]=%d\n",x,y,a[x][y]);
//printf("2.x=%d y=%d cnt=%d pre=%d\n",x,y,cnt,pre);
while(!pq.empty()) pq.pop();
tmp={sx,sy,-1};pq.push(tmp);
vis[sx][sy]=1;
while(!pq.empty())
{
tmp=pq.front();pq.pop();
if(tmp.x==ex&&tmp.y==ey&&tmp.turn<=k) { flag=1;return ; }
p.turn=tmp.turn+1;
R(i,0,4)
{
int xx=tmp.x+dir[i][0],yy=tmp.y+dir[i][1];
while(check(xx,yy))
{
if(!vis[xx][yy])
{
vis[xx][yy]=1;
//printf("3.a[%d][%d]=%d turn=%d i=%d\n",xx,yy,a[xx][yy],cnt1,i);
p.x=xx,p.y=yy;
pq.push(p);
}
xx+=dir[i][0],yy+=dir[i][1];
}
}
// printf("3.x=%d y=%d cnt=%d pre=%d\n",xx,yy,cnt,pre);
//if(pre!=i) dfs(xx,yy,cnt+1,i);else dfs(xx,yy,cnt,i);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
F(i,1,n)
{
scanf("%s",s);
for(int j=0;s[j]!='\0';++j)
{
if(s[j]=='.') a[i][j+1]=1;
else a[i][j+1]=0;
}
}
scanf("%d %d %d %d %d",&k,&sy,&sx,&ey,&ex);
if(a[sx][sy]!=a[ex][ey]) { flag=0;goto L; }
flag=0;mem(vis,0);
bfs();
L:if(flag) puts("yes");else puts("no");
}
return 0;
}
一直地一直地往前走