1 条题解

  • 0
    @ 2025-8-24 22:26:32

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Starlight237
    [Drawer/auth]EgcqEzGZV+k435xMKiYIpABsjWY0ln/huv6DW7QW9Qw=

    搬运于2025-08-24 22:26:32,当前版本为作者最后更新于2021-10-29 14:44:27,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    对于两个 9×99\times9 数独谜题(不管是否有解)A,BA,B,定义 AABB 等价当且仅当 AA 可以通过下列操作进行若干次变换后成为 BB

    • 选择两个数字 x,yx,y,将所有 xx 变成 yy,所有 yy 变成 xx
    • (1,2,3),(4,5,6),(7,8,9)(1,2,3),(4,5,6),(7,8,9) 三个三元组中,选择两个,作为整体交换以它为下标的行。
    • 选择在同一个三元组中的两个数 x,yx,y,交换谜题的第 xx 行和第 yy 行。
    • (1,2,3),(4,5,6),(7,8,9)(1,2,3),(4,5,6),(7,8,9) 三个三元组中,选择两个,作为整体交换以它为下标的列。
    • 选择在同一个三元组中的两个数 x,yx,y,交换谜题的第 xx 列和第 yy 列。
    • AA 转置。

    现在给定 n(n20)n(n\le20) 个数独谜题,判断它们两两是否等价。若等价,还需要输出一种变换的方法。D x y 表示将两个数字交换,R a b 表示整体交换三元组 (3a2,3a1,3a),(3b2,3b1,3b)(3a-2,3a-1,3a),(3b-2,3b-1,3b) 对应的行,r a b 表示交换两个行,同理有 C a bc a b 作为列操作。F 表示取转置。

    下面考虑如何比较两个数独 A,BA,B,首先不考虑具体的数字,交换行的操作一共有 1296 种,交换列的操作也一共有 1296 种。AA 同时做行变换和列变换等价于 AA 只做行变换,BB 只做列变换,因此可以把 AA 做行变换的结果用 Hash 表存起来即可,然后枚举对 BB 的列变换,看 BB' 是否在 Hash 表中出现过。类似 BSGS 算法的思想。

    转置操作最多会进行一次,枚举是否转置即可。

    由于任意两个数字可以交换,我们只需要设计一种对数值不敏感的 Hash,比如 H(s1,...,s9)=H0(s1)+...+H0(sn)H(s_1,...,s_9)=H_0(s_1)+...+H_0(s_n),或者异或等,其中 sis_i 表示数字 ii 在数独上出现的位置集合,可以用一个 unsigned int128 压缩起来。若比较的时候发现两个 Hash 值不相等,那一定(在当前变换方法下)不等价,否则暴力比较两个 {si}\{s_i\} 集合。具体实现可以用 std::mapstd::unordered_mapSTL 结构。H0H_0 是一个单值 Hash 函数,可以随自己的喜好实现。

    • 1

    信息

    ID
    6233
    时间
    2000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者