N数码问题
简介
我们先引入一个简单的问题.
首先,这里的拼图游戏是滑块拼图,类似于华容道,游戏者通过移动拼图块将拼图还原为初始形状。关于拼图,常见的有3x3,4x4,多的以至于有16x16不等。一般块数越多拼图越复杂。
如图所示,我们可以用空格与其上下左右相邻的位置的方块进行交换.给你两个局面,问这两个局面能不能互相转化.
分析
这个就是著名的N数码问题,我们为了严谨,在之后的讨论中都是N*M的矩阵.
先上结论:
(状态A忽略空格时求出的逆序对数量+状态A将空格移动到状态B所需的行数*(A的列数%2+1))%2 == (状态B忽略空格时求出的逆序对的数量)%2
如果成立,那么就可以转化.
看着有些复杂
-
如果列是奇数
(状态A忽略空格时求出的逆序对数量)%2 == (状态B忽略空格时求出的逆序对的数量)%2
-
如果列是偶数
(状态A忽略空格时求出的逆序对数量+状态A将空格移动到状态B所需的行数)%2 == (状态B忽略空格时求出的逆序对的数量)%2
简单证明
注:下文提到的"逆序对"无特殊说明都是指不算入空格在内的.
我们发现,在一行内部,无论怎样左右交换,都不会影响整个数组的逆序对数量.
所以我们就只用关心竖直交换给逆序对带来的影响.我们将空格上下移动一行,除了交换的数外,会影响M-1个其他的数的逆序对.
我们假设M-1个其他数中,有p个比当前数(我们称之为cur)小,有q个比cur大.
假设交换之前的逆序对数量是num,假设交换是cur向下交换.
对于M是奇数,M-1是偶数的情况来说
p和q要么都是奇数,要么都是偶数.cur与空格交换之后,cur的逆序对会增加q;然后对于q个数来说,逆序对数不变;对于p个数来说,逆序对数共减少了p;
则总共的变化是 q-p,根据上文的讨论,这是个偶数,所以挪动一次不影响整体逆序对的的奇偶性.
对于M是偶数,M-1是奇数的来说
p和q中有一个是奇数,一个是偶数,则q-p一定是奇数,则一次上下的挪动一定会改变奇偶性,然而我们可以这样想:我们一上来就将A的空格挪至和B相同的位置,然后无论怎么挪动,如果A能挪动到和B局面完全一样的话,这个空格一定会再次回到这个位置,也就是从这个位置出发,再回到这个位置就一定需要经历偶数次挪动(水平也是偶数,竖直也是偶数),所以从奇偶性角度来看,竖直方向的挪动就是A直接挪到B的空格的位置所需的操作
综上所述,仅M是偶数时,才需要考虑竖直方向的挪动 .
HDU 6620
AC代码
#include<bits/stdc++.h>
#define sc scanf
#define pr printf
#define pb push_back
#define ll long long