apo算法编程和蓝桥杯_apo算法编程和蓝桥杯

apo算法编程和蓝桥杯_apo算法编程和蓝桥杯兰顿蚂蚁,是于1986年,由克里斯·兰顿提出来的,属于细胞自动机的一种

历届试题 兰顿蚂蚁

问题描述

兰顿蚂蚁,是于 1986 年,由克里斯·兰顿提出来的,属于细胞自动机的一种。
平面上的正方形格子被填上黑色或白色。在其中一格正方形内有一只“蚂蚁”。
蚂蚁的头部朝向为:上下左右其中一方。
兰顿蚂蚁
蚂蚁的移动规则十分简单:
若蚂蚁在黑格,右转 90 度,将该格改为白格,并向前移一格;
若蚂蚁在白格,左转 90 度,将该格改为黑格,并向前移一格。

规则虽然简单,蚂蚁的行为却十分复杂。刚刚开始时留下的路线都会有接近对称,像是会重复,但不论起始状态如何,蚂蚁经过漫长的混乱活动后,会开辟出一条规则的“高速公路”。
蚂蚁的路线是很难事先预测的。
你的任务是根据初始状态,用计算机模拟兰顿蚂蚁在第n步行走后所处的位置。

输入格式

输入数据的第一行是 m , n m, n m,n 两个整数( 3 < m , n < 100 3 < m, n < 100 3<m,n<100),表示正方形格子的行数和列数。
接下来是 m m m 行数据,每行数据为 n 个被空格分开的数字。0 表示白格,1 表示黑格。
接下来是一行数据: x   y   s   k x\ y\ s\ k x y s k, 其中 x   y x\ y x y 为整数,表示蚂蚁所在行号和列号(行号从上到下增长,列号从左到右增长,都是从 0 开始编号)。 s s s 是一个大写字母,表示蚂蚁头的朝向,我们约定:上下左右分别用:UDLR 表示。 k k k 表示蚂蚁走的步数。

输出格式

输出数据为两个空格分开的整数 p   q p\ q p q, 分别表示蚂蚁在 k k k 步后,所处格子的行号和列号。

样例输入

5 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
2 3 L 5

样例输出

1 3

样例输入

3 3
0 0 0
1 1 1
1 1 1
1 1 U 6

样例输出

0 0


分析:

由于题目的要求是求解蚂蚁行走的最终坐标,因此很容易想到用搜索算法进行求解
而从数据范围看,更能确定该题适用 dfs 算法,不过和传统的走迷宫类题相比,该题不是以走到某个点为终止条件,而是以走了多少步为结束条件
那么我们的处理时,主要就有以下两种方案:

  1. 在dfs函数的参数列表中多加一个int型参数k,以指示当前还有多少步可走,一旦k=0就return
  2. 将模拟行走的那部分代码放进一个循环中,该循环的次数即为蚂蚁行走的步数k


—— 分割线之DFS求解 ——

方案 1 就是对 dfs 函数进行一个次数的限定,该限定值由传递进的参数 k k k 决定
本题的 dfs 和走迷宫的略有不同,该 dfs 不是以找终点为目的,因此在 dfs 时不需要往 4 个方向进行发散和搜索。由于蚂蚁会有一个固定的朝向,因此本题的 dfs 方向就是以这个朝向为准则进行的。由于题目中蚂蚁行走时有规律:

  • 若蚂蚁在黑格,右转 90 度,将该格改为白格,并向前移一格;
  • 若蚂蚁在白格,左转 90 度,将该格改为黑格,并向前移一格。

因此我们就需要对这两个规则进行解析与实现。

首先第一点是格子的黑白两种状态,这个正好可以用 bool 型二维数组来实现;
然后是蚂蚁左(或右)转的行为,这个的实现也很简单。我们首先将四个朝向进行一个规则的排列,比如我在程序中规定:U(即朝上)用数字 0 来表示,R(即朝右)用数字 1 来表示,D(即朝下)用数字 2 来表示,L(即朝左)用数字 3 来表示。
如此,我们就可以在已知某个朝向时,将这个朝向对应的数字得出(设为 D i r Dir Dir),并且在后面用 D i r Dir Dir 来表示当时的朝向状态。若蚂蚁处于黑格,则更新 D i r = ( D i r + 1 ) Dir=(Dir+1)%4 Dir=(Dir+1),这样就实现了蚂蚁的右转;若蚂蚁处于白格,则更新 D i r = ( D i r − 1 ) < 0 ? 3 : ( D i r − 1 ) Dir=(Dir-1)<0?3:(Dir-1) Dir=(Dir1)<0?3:(Dir1),这样就实现了蚂蚁的左转。最后,我们就根据上面的这个规则进行 dfs,直到最终 k = 0 k=0 k=0 时,我们输出蚂蚁所在的坐标即可。

下面给出用搜索算法求解本题的完整代码:

#include<iostream>
using namespace std;

const int N=105;
bool map[N][N];
int m,n;
int go[][2]={ 
   { 
   -1,0},{ 
   0,1},{ 
   1,0},{ 
   0,-1}}; 

int getDir(char s)							//按时针排序行走方向 
{ 
   
	switch(s){ 
   
		case 'U': return 0;
		case 'R': return 1;
		case 'D': return 2;
		case 'L': return 3; 
	}
}
void dfs(int x,int y,int dir,int k)			//(x,y)表示蚂蚁的坐标,s指示了朝向的代码,k表示步数 
{ 
   
	if(k==0){ 
   
		cout<<x<<" "<<y<<endl;
		return;
	} 
	if(map[x][y]) dir=(dir+1)%4;			//黑格则右转(增加) 
	else dir=((dir-1)<0?3:(dir-1));			//白格则左转(减少)
	map[x][y]=!map[x][y];					//改变当前格子颜色 
	x+=go[dir][0],y+=go[dir][1];			//更新蚂蚁坐标 
	dfs(x,y,dir,--k); 						//继续行走 
}

int main()
{ 
   
	char s;
	int x,y,k;
	cin>>m>>n;
	for(int i=0;i<m;i++)
		for(int j=0;j<n;j++)
			cin>>map[i][j];					//0表示白格,1表示黑格 
	cin>>x>>y>>s>>k;
	dfs(x,y,getDir(s),k);
	return 0;
}


—— 分割线之迭代求解 ——

实际上,本题中的地图并不严格依赖前面行走后的信息,它仅仅关心下一个所在坐标的颜色和自身的朝向问题。而这些工作通过迭代也是能够实现的,因此才有了前面的第 2 点的方案
方案 2 主要是通过在迭代中,不断更新当前所处位置的坐标以及整个地图中的黑白格,直至最终 k = 0 k=0 k=0,最后再输出位置坐标即可,下面给出用迭代方法求解本题的完整代码:

#include<iostream>
using namespace std;

const int N=105;
bool map[N][N];
int m,n;
int go[][2]={ 
   { 
   -1,0},{ 
   0,1},{ 
   1,0},{ 
   0,-1}}; 

int getDir(char s)							//按时针排序行走方向 
{ 
   
	switch(s){ 
   
		case 'U': return 0;
		case 'R': return 1;
		case 'D': return 2;
		case 'L': return 3; 
	}
}
void Run(int x,int y,int dir,int k)
{ 
   
	while(k--)
	{ 
   							
		if(map[x][y]) dir=(dir+1)%4;		//黑格则右转(增加) 
		else dir=((dir-1)<0?3:(dir-1));		//白格则左转(减少)
		map[x][y]=!map[x][y];				//改变当前格子颜色
		x+=go[dir][0],y+=go[dir][1];		//更新蚂蚁坐标 
	}
	cout<<x<<" "<<y<<endl;
}

int main()
{ 
   
	char s;
	int x,y,k,dir;
	cin>>m>>n;
	for(int i=0;i<m;i++)
		for(int j=0;j<n;j++)
			cin>>map[i][j];					//0表示白格,1表示黑格 
	cin>>x>>y>>s>>k;
	Run(x,y,getDir(s),k); 
	return 0;
}

END


今天的文章apo算法编程和蓝桥杯_apo算法编程和蓝桥杯分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/83641.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注