题意
给出一个图,有石头和空地,有一个球,可以向上下左右任意一个没有相邻石头的方向持续移动,直到撞到石头为止(球停留在石头的前一格),并且会使撞到的石头消失,求让球到达目的地最少的步数(不一定非要在终点停下,经过即可视为抵达),且步数必定小于等于10,否则算无解。如果没有合法方案,也属于无解,无解输出-1
题解
因为步数必然小于10,所以枚举每一步走上下左右的某一个方向即可,判断是否合法,然后转移。
时间复杂度为4的n次方,n<=10。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 30
using namespace std;
int ma[MAXN][MAXN],n,m,w[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
queue<pair<int,int> >q;
pair<int,int> st,ed;
int get_lx(int x,int y,int f){
if(f==0)
return x;
int x1=x+f;
while(ma[x1][y]!=1&&x1>=0&&x1<=n+1){
if(x1==ed.first&&y==ed.second){
x1+=f;
break;
}
x1+=f;
}
return x1-f;
}
int get_ly(int x,int y,int f){
if(f==0)
return y;
int y1=y+f;
while(ma[x][y1]!=1&&y1>=0&&y1<=m+1){
if(x==ed.first&&y1==ed.second){
y1+=f;
break;
}
y1+=f;
}
return y1-f;
}
int check1(int x,int y){
if(x*y==0||x>n||y>m)
return 0;
if(ma[x][y]==1)
return 0;
return 1;
}
int dfs(int x,int y,int cnt){
//PF("(%d %d %d)\n",x,y,cnt);
if(cnt>10)
return 11;
if(x==ed.first&&y==ed.second)
return cnt;
int res=11;
for(int i=0;i<4;i++){
if(check1(x+w[i][0],y+w[i][1])==0)
continue;
int x1=get_lx(x,y,w[i][0]);
int y1=get_ly(x,y,w[i][1]);
if(check1(x1,y1)){
int sig=0;
if(ma[x1+w[i][0]][y1+w[i][1]]==1)
sig=1;
ma[x1+w[i][0]][y1+w[i][1]]=0;
res=min(res,dfs(x1,y1,cnt+1));
if(sig==1)
ma[x1+w[i][0]][y1+w[i][1]]=1;
}
}
return res;
}
int main(){
SF("%d%d",&m,&n);
int x;
while(n*m!=0){
memset(ma,0,sizeof ma);
while(!q.empty())
q.pop();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
SF("%d",&x);
if(x==2)
st=make_pair(i,j);
else if(x==3)
ed=make_pair(i,j);
else if(x==1)
ma[i][j]=1;
}
int ans=dfs(st.first,st.second,0);
if(ans==11)
PF("-1\n");
else
PF("%d\n",ans);
SF("%d%d",&m,&n);
}
}