拼图游戏都玩过,
对于一个n*m的拼图游戏,我们将按照从左到右,从上到下的顺序给每个分格标注,可得一个二维矩阵。以3*3为例,标注结果如:
- 0 1 2
- 3 4 5
- 6 7 8
我们假设最大值为空白。即游戏时的样子是这样的:
- 0 1 2
- 3 4 5
- 6 7
但是不是所有的拼图都是有解的。
可解:
- 6 2 1
- 4 7 5
- 0 3 8
无解:
- 4 2 1
- 8 3 6
- 5 0 7
判断有解:
证明这里就省略了,表示看不懂,可以参加:
http://air20.com/archives/323.html
这里说下规律,设两个矩阵A和B。将矩阵从左到右,从上到下排成一个一维数组,设其逆序对的个数加上空白格在原矩阵所在的行列号之和P。若P(A)与P(B)的奇偶性相同,则两个矩阵可以通过拼图游戏进行转换。因此只要计算当前矩阵和正确矩阵的P值判断一下即可。
生成随机可解拼图游戏:
设拼图规模为n*m,用pt[n][m]表示,空白格位于pt[n-1][m-1]。
对于n*m的游戏,生成一个大小为n*m的一维数组data[n*m],空白格在data[n*m-1]。
则 p = n+m+con。其中con为data[0...n*m-2]的逆序对个数。
由于奇数+奇数=偶数,奇数+偶数=奇数,偶数+偶数=偶数,我们知道n+m的奇偶性,因此只要保证con的奇偶性即可。
随机生成data[0...n*m-2]。因为con(data[0...n*m-2])由con(data[0...n*m-4])和con(data[n*m-3...n*m=2])决定,而data[n*m-2]和data[n*m-3]的位置关系,不影响data[0...n*m-4]的奇偶性。
所以交换data[n*m-2]和data[n*m-3]会改变整个数据的逆序对个数的奇偶性。
因此只要根据随机生成的data,适当交换data[n*m-2]和data[n*m-3]的位置即可。。从这个规律也可以看出,随机的矩阵中只有一半是可解的。。
生成代码如下:
- void getKeJiePingTu(int a[vol][col]){
- int data[vol*col] = {0};
- int maxnumber = vol*col-1;
- for (int i=0;i<maxnumber;++i){
- data[i] = i;
- int replacei = rand()%(i+1);
- int t = data[i];
- data[i] = data[replacei];
- data[replacei] = t;
- }
- data[maxnumber] = maxnumber;
- //计?算?逆?序??对?数?y
- int coverPairCount = 0;
- for (int i=0;i<maxnumber;++i){
- for (int j=i+1;j<maxnumber;++j){
- if (data[i]>data[j])
- coverPairCount++;
- }
- }
- if ( (coverPairCount&1) == 1){
- int t = data[maxnumber-1];
- data[maxnumber-1] = data[maxnumber-2];
- data[maxnumber-2] = t;
- }
- int index = 0;
- for (int i=0;i<vol;++i){
- for (int j=0;j<col;++j){
- a[i][j] = data[index++];
- }
- }
- }