QOJ 12255 - 36 Puzzle 题解

题意

给定一个 6×66\times 66×6 的网格图,每格分别不重复地填入了一个 1∼361\sim 361∼36 的数字。你每次可以选择一行或一列,对其向上或向下(选择列),向左或向右(选择行)循环位移,使得最终这个网格图是顺排的,即第 iii 行第 jjj 列的数是 (i−1)×n+j(i-1)\times n+j(i−1)×n+j。数据保证有解,构造出一种可行方案。本题题把 1∼361\sim 361∼36 映射到了 a∼z,0∼9\tt{a}\sim\tt{z},\tt{0}\sim{9}a∼z,0∼9,共 363636 个字符上。

例:

方法 1

发现要想交换 (x,y)(x,y)(x,y) 和 (x,y+1)(x,y+1)(x,y+1),可对第 xxx 行 / 第 yyy 列执行 ULURULURULURU 操作。要想交换 (x,y)(x,y)(x,y) 和 (x+1,y)(x+1,y)(x+1,y),可对第 xxx 行 / 第 yyy 列执行 LULDLULDLULDL 操作。实现邻项交换后,我们只要从上往下、从左往右地做就可以了。

cpp 复制代码
int to[200], id[7][7], a[7][7];
void init(){
    for (int i = 'a'; i <= 'z'; i++) to[i] = i - 'a' + 1;
    for (int i = '0'; i <= '9'; i++) to[i] = i - '0' + 27;
}
void f(int x, int y){
    string seq = "LULDLULDLULDL";
    for (char c : seq) cout << (c == 'L' || c == 'R' ? x : y) << " " << c << " 1\n";
}
void g(int x, int y){
    string seq = "ULURULURULURU";
    for (char c : seq) cout << (c == 'L' || c == 'R' ? x : y) << " " << c << " 1\n";
}
void solve(){
    init();
    int n = 6;
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++){
            char c; cin >> c;
            a[i][j] = to[c];
            id[i][j] = (i - 1) * n + j;
        }
    }
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++){
            int ni = -1, nj = -1;
            for (int x = 1; x <= n; x++) for (int y = 1; y <= n; y++) if (a[x][y] == id[i][j]) ni = x, nj = y;
            // 注意此处必须先调整列数,再调整行数
            while (nj > j){
                g(ni, nj - 1);
                swap(a[ni][nj - 1], a[ni][nj]);
                nj--;
            }
            while (nj < j){
                g(ni, nj);
                swap(a[ni][nj + 1], a[ni][nj]);
                nj++;
            }
            while (ni > i){
                f(ni - 1, nj);
                swap(a[ni][nj], a[ni - 1][nj]);
                ni--;
            }
        }
    }
}

方法 2(简述)

根据魔方公式 R,U,R′,U′R,U,R',U'R,U,R′,U′ 给我们的灵感,发现如果执行 RULD 可以交换 LLL 形的三个块,R..RUL..LD 等方式可以交换任意三个形成直角三角形的块。这样我们可以直接从上往下做,直到最后一行。发现选择三个东西做两次上述交换:

就可以实现同一行的三个东西轮换。然后我们发现长度为 666 的置换是奇置换,所以任意给定的网格图都是有解的。

相关推荐
mmmmath_34 小时前
LeetCode.199.二叉树的右视图
数据结构·leetcode
专注仿真4 小时前
引擎扩展性与集成设计深度剖析:从 14 个扩展点到 DIS→HLA 演进之路
开发语言·算法·仿真引擎·推演引擎
码爸4 小时前
支持向量机介绍与示例
算法·机器学习·支持向量机
怕浪猫4 小时前
2028编程圈很火的10个Skills
算法·面试·github
fxss5 小时前
宝宝学识屋上新|用喜欢的小动物,玩懂数数、加法和减法
数学
别动我齐刘海6 小时前
Linux 系统调试学习1
linux·运维·服务器·c++·学习·机器学习·机器人
Nil2089 小时前
leetcode 198打家劫舍
算法·leetcode·职场和发展
Shaoshing9 小时前
前缀和与差分
java·数据结构·算法·前缀和·差分
mmmmath_39 小时前
LeetCode.429.N叉树的层序遍历
数据结构·leetcode
loulanyue_10 小时前
构建房产认知决策智能:Harness底座与AI自进化的技术实践——读贝壳首席算法科学家尹俊希2026云栖专场演讲
人工智能·算法