0
点赞
收藏
分享

微信扫一扫

蓝桥杯 算法训练 跳马

梯梯笔记 2022-02-25 阅读 57

蓝桥杯 算法训练 跳马

题目描述

  • 资源限制
    时间限制:1.0s 内存限制:256.0MB
  • 问题描述
    一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?
  • 输入格式
    一行四个数字a,b,c,d。
  • 输出格式
    如果跳不到,输出-1;否则输出最少跳到的步数。
  • 样例输入
    1 1 2 3
  • 样例输出
    1
  • 数据规模和约定
    0<a,b,c,d≤8且都是整数。

方案1 方案1 递归搜索,dfs

#include<iostream>

using namespace std;

int a, b;				//起始坐标 (a,b)	
int c, d;				//终止坐标 (c,d)
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};	//马每走一次可能的x坐标的变化 
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1};	//马每走一次可能的y坐标的变化 
int ans;				//从起点到终点所需要的最少步数,无法抵达则输出-1 
bool flag[8][8];		//flag[i][j]=true 表明坐标(i+1,j+1)已经来过 

//函数功能:已知起点(a, b), 终点(c, d), 返回起点到终点所需要的最少步数,无法抵达则返回-1 
int f(int a, int b, int c, int d, bool flag[8][8]){
	//如果越界或者曾经到过该坐标,认为最小值不可能在此处出现,故返回-1 
	if(a<=0 || a>8 || b<=0 || b>8 || c<=0 || c>8 || d<=0 || d>8 || flag[a-1][b-1]==true){
		return -1;
	} 
	
	//如果到达终点,则返回步数0 
	if(a==c&&b==d){
		return 0;
	} 
	
	flag[a-1][b-1] = true;		//记录该坐标已经来过
	 
	int temp, min=64;	//不可能超过64步 
	for(int i=0; i<8; i++){
		//记录下一步到达终点所需的最小步数 
		temp = f(a+dx[i], b+dy[i], c, d, flag);
		// 如果可达,则更新最小步数 
		if(temp != -1){
			min = min>temp+1?temp+1:min;
		} 
	}
	//如果没有被更新,说明该坐标的下一步均不符合题意 
	if(min==64){
		return -1;
	}else{	//反之则存在符合题意的最小值 
		flag[a-1][b-1] = false;		//恢复现场 
		return min;
	}
} 

int main(){
	cin>>a>>b>>c>>d;
	
	cout<<f(a, b, c, d, flag)<<endl;
	
	return 0; 
} 

//方案2 dfs 非递归 压栈

#include<iostream>
#include<stack> 
#include<string>
#include<cmath>
#include<algorithm>

using namespace std;

int a, b;				//起始坐标 (a,b)	
int c, d;				//终止坐标 (c,d)
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};	//马每走一次可能的x坐标的变化 
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1};	//马每走一次可能的y坐标的变化 
int ans[8][8];			//ans[i][j] 表明坐标起点到(i+1,j+1)的最短步数 

//函数功能:假设a=2, b=3, c=4, 返回"2_3_4" 
string int2str(int a, int b, int c){
	string ans;
	while(c!=0){
		ans += char(c%10+'0');
		c/=10; 
	}
	ans += '_';
	while(b!=0){
		ans += char(b%10+'0');
		b/=10; 
	}
	ans += '_';
	while(a!=0){
		ans += char(a%10+'0');
		a/=10; 
	}
	reverse(ans.begin(), ans.end());		//反转 
	return ans;
}

//函数功能:假设s="2_3_4", 返回ans=[2, 3, 4] 
void str2int(string s, int ans[]){
	int i=0;
	string a, b, c;
	while(s[i]!='_'){
		a+=s[i];
		i++;
	}
	i++;
	while(s[i]!='_'){
		b+=s[i];
		i++;
	}
	i++;
	while(i<s.length()){
		c+=s[i];
		i++;
	}
	i = 0;
	while(i<a.length()){
		ans[0]+=(a[i]-'0')*pow(10, a.length()-i-1);
		i++;
	}
	i = 0;
	while(i<b.length()){
		ans[1]+=(b[i]-'0')*pow(10, b.length()-i-1);
		i++;
	}
	i=0;
	while(i<c.length()){
		ans[2]+=(c[i]-'0')*pow(10, c.length()-i-1);
		i++;
	}
}

//函数功能:已知起点(a, b), 计算起点到任意点所需要的最少步数,无法抵达则返回-1 
void f(int a, int b, int ans[8][8]){
	//从起点到任一点所需要的最少步数,并初始化为最大值64 
	for(int i=0; i<8; i++){
		for(int j=0; j<8; j++){
			ans[i][j] = 64;
		}
	}
	
	stack<string> st;				//栈空间 
	st.push(int2str(a, b, 0));		//压栈(a,b), 0是步数 
	while(st.size()>0){
		int temp[3] = {0};
		str2int(st.top(), temp);
		st.pop();
		a = temp[0];
		b = temp[1];

		//更新最小步数
		ans[a-1][b-1] = min(ans[a-1][b-1], temp[2]); 
		
		for(int i=0; i<8; i++){
			//如果下一步没越界且下一步的步数比下一位置的最小步数小,则把下一步压进栈
			if(a+dx[i]>0 && a+dx[i]<=8 && b+dy[i]>0 && b+dy[i]<=8 && (temp[2]+1)<ans[a+dx[i]-1][b+dy[i]-1]){
				st.push(int2str(a+dx[i], b+dy[i], temp[2]+1));
			}  
		}
	}
	
	//如果最小步数 = 64,认为不可达,更新为-1 
	for(int i=0; i<8; i++){
		for(int j=0; j<8; j++){
			ans[i][j] = ans[i][j]==64?-1:ans[i][j];
		}
	}
} 

int main(){
	cin>>a>>b>>c>>d;
	f(a, b, ans);
	cout<<ans[c-1][d-1]<<endl;
	return 0; 
} 

方案3 BFS 队列

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue> 

using namespace std;

int a, b;				//起始坐标 (a,b)	
int c, d;				//终止坐标 (c,d)
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};	//马每走一次可能的x坐标的变化
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1};	//马每走一次可能的y坐标的变化 
bool flag[8][8];		//flag[i][j]=true 表明坐标(i+1,j+1)已经来过 

//函数功能:假设a=2, b=3, c=4, 返回"2_3_4" 
string int2str(int a, int b, int c){
	string ans;
	while(c!=0){
		ans += char(c%10+'0');
		c/=10; 
	}
	ans += '_';
	while(b!=0){
		ans += char(b%10+'0');
		b/=10; 
	}
	ans += '_';
	while(a!=0){
		ans += char(a%10+'0');
		a/=10; 
	}
	reverse(ans.begin(), ans.end());		//反转 
	return ans;
}

//函数功能:假设s="2_3_4", 返回ans=[2, 3, 4] 
void str2int(string s, int ans[]){
	int i=0;
	string a, b, c;
	while(s[i]!='_'){
		a+=s[i];
		i++;
	}
	i++;
	while(s[i]!='_'){
		b+=s[i];
		i++;
	}
	i++;
	while(i<s.length()){
		c+=s[i];
		i++;
	}
	i = 0;
	while(i<a.length()){
		ans[0]+=(a[i]-'0')*pow(10, a.length()-i-1);
		i++;
	}
	i = 0;
	while(i<b.length()){
		ans[1]+=(b[i]-'0')*pow(10, b.length()-i-1);
		i++;
	}
	i=0;
	while(i<c.length()){
		ans[2]+=(c[i]-'0')*pow(10, c.length()-i-1);
		i++;
	}
}


//函数功能:已知起点(a, b), 终点(c, d), 返回起点到终点所需要的最少步数,无法抵达则返回-1 
int f(int a, int b, int c, int d, bool flag[8][8]){

	queue<string> qu;
	qu.push(int2str(a, b, 0));
	while(qu.size()>0){
		int temp[3] = {0};
		str2int(qu.front(), temp);
		qu.pop();
		a = temp[0];
		b = temp[1];
		flag[a-1][b-1] = true;
		if(a==c&&b==d){
			return temp[2];
		}
		
		for(int i=0; i<8; i++){
			//如果下一步没越界且下一步的位置没有被走过,则把下一步压进栈
			if(a+dx[i]>0 && a+dx[i]<=8 && b+dy[i]>0 && b+dy[i]<=8 && !flag[a+dx[i]-1][b+dy[i]-1]){
				qu.push(int2str(a+dx[i], b+dy[i], temp[2]+1));
			}  
		}
	}
	return -1;
} 

int main(){
	cin>>a>>b>>c>>d;
	
	cout<<f(a, b, c, d, flag)<<endl;
	
	return 0; 
} 
举报

相关推荐

0 条评论