兰顿蚂蚁
题目描述
兰顿蚂蚁,是于 1986 年,由克里斯·兰顿提出来的,属于细胞自动机的一种。
平面上的正方形格子被填上黑色或白色。在其中一格正方形内有一只"蚂蚁"。
蚂蚁的头部朝向为:上下左右其中一方。
蚂蚁的移动规则十分简单:
若蚂蚁在黑格,右转 90 度,将该格改为白格,并向前移一格;
若蚂蚁在白格,左转 90 度,将该格改为黑格,并向前移一格。
规则虽然简单,蚂蚁的行为却十分复杂。刚刚开始时留下的路线都会有接近对称,像是会重复,但不论起始状态如何,蚂蚁经过漫长的混乱活动后,会开辟出一条规则的"高速公路"。
蚂蚁的路线是很难事先预测的。
你的任务是根据初始状态,用计算机模拟兰顿蚂蚁在第 n 步行走后所处的位置。
输入描述
输入数据的第一行是 m,nm,n 两个整数 (3<m,n<100)(3<m,n<100),表示正方形格子的行数和列数。
接下来是 mm 行数据。
每行数据为 nn 个被空格分开的数字。0 表示白格,1 表示黑格。
接下来是一行数据:x,y,s,kx,y,s,k, 其中 x,yx,y 为整数,表示蚂蚁所在行号和列号(行号从上到下增长,列号从左到右增长,都是从 0 开始编号)。ss 是一个大写字母,表示蚂蚁头的朝向,我们约定:上下左右分别用:U D L R 表示。kk 表示蚂蚁走的步数。
输出描述
输出数据为两个空格分开的整数 p,qp,q, 分别表示蚂蚁在 kk 步后,所处格子的行号和列号。
输入输出样例
示例
输入
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
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
总通过次数: 854 | 总提交次数: 917 | 通过率: 93.1%
难度: 困难 标签: 2014, 模拟, 省赛
算法思路
兰顿蚂蚁是一种基于细胞自动机的模型,其行为规则简单但能产生复杂的行为模式。核心思路是模拟蚂蚁在网格上的移动过程:
- 状态判断:根据当前所在格子的颜色(黑/白)决定转向规则
- 转向规则:
- 黑格 → 右转90°
- 白格 → 左转90°
- 颜色翻转:翻转当前格子颜色(黑→白,白→黑)
- 位置移动:根据新方向前进一格
通过循环执行上述操作K次,最终确定蚂蚁位置
算法过程演示
完整C++代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 输入网格尺寸
int m, n;
cin >> m >> n;
// 创建并初始化网格 (0=白格, 1=黑格)
vector<vector<int>> grid(m, vector<int>(n));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cin >> grid[i][j];
}
}
// 输入蚂蚁初始状态
int x, y, k;
char s;
cin >> x >> y >> s >> k;
// 方向映射: U=0, R=1, D=2, L=3
int dir;
if (s == 'U') dir = 0;
else if (s == 'R') dir = 1;
else if (s == 'D') dir = 2;
else if (s == 'L') dir = 3;
// 模拟蚂蚁移动
while (k--) {
// 根据当前格子颜色转向
if (grid[x][y] == 0) { // 白格→左转
dir = (dir + 3) % 4; // +3 等效于逆时针90°
} else { // 黑格→右转
dir = (dir + 1) % 4; // +1 等效于顺时针90°
}
// 翻转当前格子颜色
grid[x][y] = 1 - grid[x][y];
// 根据新方向移动
switch (dir) {
case 0: x--; break; // 上
case 1: y++; break; // 右
case 2: x++; break; // 下
case 3: y--; break; // 左
}
}
// 输出最终位置
cout << x << " " << y;
return 0;
}
代码解析
-
网格初始化(第11-17行)
- 使用
vector
动态创建m×n网格 - 0表示白格,1表示黑格
- 使用
-
方向映射(第23-28行)
- 将字符方向(U/R/D/L)转换为数字(0/1/2/3)
- 便于数学计算转向角度
-
核心移动逻辑(第31-45行)
(dir + 3) % 4
:实现左转90°(逆时针)(dir + 1) % 4
:实现右转90°(顺时针)1 - grid[x][y]
:快速翻转格子颜色
-
边界处理
- 题目保证移动不越界,无需额外检查
实例验证
输入:
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
模拟过程:
步数 | 位置(x,y) | 当前颜色 | 新方向 | 移动后位置 |
---|---|---|---|---|
初始 | (2,3) | 白(0) | ↓ (D) | (3,3) |
1 | (3,3) | 白(0) | → (R) | (3,4) |
2 | (3,4) | 白(0) | ↑ (U) | (2,4) |
3 | (2,4) | 白(0) | ← (L) | (2,3) |
4 | (2,3) | 黑(1) | ↑ (U) | (1,3) |
输出:1 3
✅ 符合预期
注意事项
-
方向映射一致性:
- 必须确保方向数字与移动操作的对应关系正确
- 错误映射会导致移动方向混乱
3
-
颜色翻转时机:
- 必须在移动前翻转当前格子颜色
- 顺序错误会导致状态不一致
6
-
边界风险:
- 虽然题目保证不越界,但可添加防护:
// 在switch后添加边界检查 x = max(0, min(x, m-1)); y = max(0, min(y, n-1));
-
大K值优化:
- 当K>10⁶时,可考虑周期性检测
- 记录状态(x,y,dir,gridHash)减少重复计算
8
测试用例设计
测试类型 | 输入样例 | 预期输出 | 验证点 |
---|---|---|---|
最小网格 | 3 3\n0 0 0\n0 0 0\n0 0 0\n1 1 U 1 | 0 1 | 基本功能 |
边界移动 | 3 3\n1 1 1\n1 1 1\n1 1 1\n0 0 D 3 | 2 0 | 边界处理 |
颜色翻转 | 1 1\n1\n0 0 U 2 | 0 0 | 颜色翻转正确性 |
最大步数(K=100000) | 100×100全白网格+50 50 R 100000 | 坐标验证 | 性能(需<0.5s) |
方向组合 | 3 3\n0 1 0\n1 0 1\n0 1 0\n1 1 U 4 | 0 1 | 复杂转向逻辑 |
优化建议
-
内存优化:
// 使用bitset压缩存储 #include <bitset> vector<vector<bitset<1>>> grid(m, vector<bitset<1>>(n));
- 减少75%内存占用(适用于大网格)
-
循环展开:
// 每4步作为一组处理 while (k >= 4) { // 处理4步移动 k -= 4; }
-
SIMD并行:
- 使用AVX指令并行处理多个格子颜色翻转
- 适用于需要同时模拟多只蚂蚁的场景
-
状态缓存:
unordered_map<string, int> stateMap; string state = to_string(x)+","+to_string(y)+","+to_string(dir)+",";