POJ3009 - Curling 2.0 - DFS+方向直线移动
题意
给出一个 \(m\) x \(n\) 的图,图中有 \(1\)、\(2\)、\(3\)、\(4\)数字,分别表示: \(0\) 空地、 \(1\) 障碍物、 \(2\) 起点、 \(3\) 终点。
让我们输出:从起点( \(S\) )到终点( \(G\) )的最小步数,无法达到输出 \(-1\) 。
要求:
-
仅限 \(x\) 和 \(y\) 方向(即禁止对角线移动)。
-
石头一旦开始移动,只能沿着这一个方向一直移动,除非下列任一事件发生:
-
石头击中黑色方块。
-
石块飞出游戏板之外(即超出图的边界)。
-
石头停在他击中的砖块之前被击中的砖块消失(也就是说,如果石头走到障碍物的四周,那么可以换方向走,该障碍物消失变成空地 \(0\))。
-
-
步数不能超过 \(10\) 步。
思路
正确的思路是:先找到起点 \(S\) ,然后将该点由 \(2\) 变为 \(0\) ,表示是空地,可以走(本来也可以走)。
然后开始从 \(S\) 开始搜,
关键点主要是:不一次一格走,而是一次一条线走,该如何写?其实通过一个while和一个方向累加就行了,
while(tx>=1&&tx<=n&&ty>=1&&ty<=m&&a[tx][ty]==0)
tx+=to[i][0],ty+=to[i][1];
之后如果碰到终点了,那么直接 更新+return 就行了。
排除所有碰到终点呀、越界呀这些情况,最后开始继续往下搜,首先把障碍物消除,变为空地 \(0\) ,搜索,把障碍物还原变为 \(1\) 。
其实我的思路是BFS,因为求最小步数嘛,但是我不会写……
这是我写的BFS部分代码:
#include<iostream>
#include<cmath>
#include<string.h>
#include<queue>
using namespace std;
typedef long long ll;
#define inf 03f3f3f3f
char s[22][22];
int n,m,s,t,ss,tt;
bool book[22][22];
int to[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
typedef pair<int,int>P;
int bfs()
{
memset(dis,inf,sizeof(dis));
dis[s][t]=0;
queue<P>Q;
Q.push(P(s,t));
while(!Q.empty())
{
P x=Q.front();
Q.pop();
if(x.first==ss&&x.second==tt)
break;
for(int i=0;i<4;i++)
{
int tx=x.first+to[i][0];
int ty=x.second +to[i][1];
if(tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]!='#'&&d[tx][ty]==inf)
{
Q.push(P(tx,ty));
dis[tx][ty]=dis[x.first][x.second]+1;
}
}
}
return dis[ss][tt];
}
int main()
{
while(cin>>m>>n)
{
if(m==0&&n==0)
break;
for(int i=0;i<n;i++)
{
scanf("%s",s[i]);
for(int j=0;j<m;j++)
{
if(s[i][j]=='S')
s=i,t=j;
else if(s[i][j]=='G')
ss=i,tt=j;
}
}
int w=bfs();
if(w==inf)
cout<<-1<<endl;
else
cout<<w<<endl;
}
return 0;
}
AC代码
#include<iostream>
#include<cmath>
#include<string.h>
#include<queue>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
int a[22][22],n,m,s,t,ss,tt,ans;
bool book[22][22];
int to[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
typedef pair<int,int>P;
void dfs(int x,int y,int step)
{
if(step>=ans||step>=10) return ;
for(int i=0;i<4;i++)
{
int tx=x+to[i][0];
int ty=y+to[i][1];
if(a[tx][ty]==1) // 遇到障碍物
continue ;
while(tx>=1&&tx<=n&&ty>=1&&ty<=m&&a[tx][ty]==0)
tx+=to[i][0],ty+=to[i][1];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m)
{
if(a[tx][ty]==3) // 0空地、1障碍物、2起点、3终点
{
ans=step+1;
return ;
}
a[tx][ty]=0; //消去障碍物
dfs(tx-to[i][0],ty-to[i][1],step+1);
a[tx][ty]=1;
}
}
}
int main()
{
while(cin>>m>>n)
{
if(m==0&&n==0)
break;
//0空地、1障碍物、2起点、3终点
ans=inf;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
if(a[i][j]==2)
a[i][j]=0,s=i,t=j;
}
}
dfs(s,t,0);
if(ans!=inf)
cout<<ans<<endl;
else
cout<<-1<<endl;
}
return 0;
}