穿越雷区

题目:

X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。
某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?

已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。
例如:

A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -

输入:

输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,中间用空格分开。
A,B都只出现一次。

输出:

要求输出一个整数,表示坦克从A区到B区的最少移动步数。
如果没有方案,则输出-1
坦克车只能水平或垂直方向上移动到相邻的区。

分析:

这道题整体来说还是一道搜索题,有点类似解救小哈那道题,就是dfs的话有点麻烦的地方是如何处理题目中它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,我把+、-处理成为1、-1,A、B处理成为0.

定义变量p,p的取值是-1、1也就是代表正负辐射状态。如果(x,y)的a[x][y]=1,我令p=-a[x][y]=-1,也就是说下一个搜索的坐标(tx,ty)的 a[tx][ty]=p=-1.这样就确保了正负交替。但是这样会导致A、B两个点无法满足条件,因为题目说了AB是安全区,也就是A、B两点的坐标对应数组的值为0.所以要进行特判。

代码:

#include<bits/stdc++.h>
using namespace std;
int Min=99999999;//用来更新最小值
int a[101][101],book[101][101];//book标记走过的路
int x,y,x2,y2;//(x,y)标记A的坐标、(x2,y2)标记B的坐标。
int n;//矩阵大小n*n
char s;//存储临时字符

void dfs(int x,int y,int step){

	int next[4][2]={{0,1},{1,0},{-1,0},{0,-1}};//定义方向数组
	int tx,ty;//定义下一个要搜索的坐标

	for (int i=0;i<=3;i++){//循环(x,y)的右下左上坐标
		tx=x+next[i][0];
		ty=y+next[i][1];
		//超出边界即跳过本次循环执行下一次
		if ( tx>n || ty>n || tx<1 || ty<1)
		continue;
		
		if (tx==x2 && ty==y2){//这里之所以把满足条件更新Min放在循环内是因为下面的B点没有办法被搜素到,所以用下一个将要搜索的点来判断,step+1也是因为B点没有被dfs所以要加1.
			if (step+1<Min)
			Min=step+1;
			return;
		}

		int p;
		p=a[x][y];
		p=0-p;//这个p就是本题的重点了,(p==0 && step==0)就是特判从A点进入辐射区。然后就是如果搜索到了B点该怎么办?我们知道B点的状态是a[tx][ty]=0,B点的0肯定和辐射区的1、-1不相等,所以B点不能进入dfs。
		if ((a[tx][ty]==p && book[tx][ty]==0) ||(p==0 && step==0)){
			book[tx][ty]=1;//标记走过的点
			dfs(tx,ty,step+1);
			book[tx][ty]=0;//一次深搜结束后取消标记
		}
	}
	return;//回溯,如果到这个点上下左右都不能走,回到上一个点。
} 
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++){
			cin>>s;
			if (s=='+')
			a[i][j]=1;
			if (s=='-')
			a[i][j]=-1;
			if (s=='A')
			x=i;y=j;
			if (s=='B')
			x2=i;y2=j;
		}
		//处理矩阵并且标记A、B坐标。
	dfs(x,y,0);//从A的坐标开始搜索。
	if (Min==99999999){
		cout<<-1;
	}
	else
	cout<<Min;
    return 0;
}

posted @ 2020-10-15 19:50  Treasure_lee  阅读(200)  评论(0)    收藏  举报