历届试题 兰顿蚂蚁
问题描述
兰顿蚂蚁,是于 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 算法,不过和传统的走迷宫类题相比,该题不是以走到某个点为终止条件,而是以走了多少步为结束条件
那么我们的处理时,主要就有以下两种方案:
- 在dfs函数的参数列表中多加一个int型参数k,以指示当前还有多少步可走,一旦k=0就return
- 将模拟行走的那部分代码放进一个循环中,该循环的次数即为蚂蚁行走的步数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=(Dir−1)<0?3:(Dir−1),这样就实现了蚂蚁的左转。最后,我们就根据上面的这个规则进行 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