滑块拼图
描述
问题变为判定从初始局
5 2 8
1 3 0
4 6 7
变为目标局
5 2 8
1 3 7
4 6 0
是否有解的。0代表空格
输入
2个3×3的数字矩阵,一共6行。
每行是3个数字。
前三行代表初始局,后三行代表目标局。
数字0代表X的位置
输出
如果有解输出possible
否则输出impossible
输入样例
7 3 5
0 1 6
8 4 2
3 2 8
4 6 5
1 0 7
输出样例
possible
解法
一共有多少种排列组合方式?
把空格也当成一个滑块,一共有 n×m 个互不相同的滑块
所以答案是:(n×m)!
如果是3×3的九宫格那么组合方式有
9!=362880
如何判断一种组合是合法的?
把方格降维考虑
N=逆序数对之和(不算空格)
e=空格所在的行数
合法性判定:
若n为奇数,当且仅当 N为偶数时合法
若n为偶数,当且仅当 N+e为偶数 时合法
命题1:当n为奇数时,移动后N奇偶性不变
证明:
当N为奇数的时候有结论如下:
如何判断两个N×N矩阵S和T可否相互变换?
-
求两个N×N矩阵S和T的逆序数 rS和rT(扣除空格后)
-
若R1与R2奇偶性相同,则可以相互变换,否则不可能
综上所诉(重要的事情说三遍!!!)
题意转化成求两个两个九宫盘的逆序对个数,如果两个奇偶性相同,则possible
代码
#include<bits/stdc++.h>
using namespace std;
int a[1000]; //输入数据
int b[1000]; //临时数组
void Merge(int a[],int low,int mid,int high,int tmp[])
{
int pTmp = 0;
int p1 = low, p2 = mid + 1;
while(p1<=mid && p2<=high){
if(a[p1]>a[p2])
tmp[pTmp++] = a[p1++];
else
tmp[pTmp++] = a[p2++];
}
while(p1<=mid)
tmp[pTmp++] = a[p1++];
while(p2<=high)
tmp[pTmp++] = a[p2++];
for(int i=0;i<high-low+1;i++)
a[low+i]=tmp[i];
}
long long Count(int a[],int low,int mid,int high){
long long resTarget = 0;
int p1 = low,p2 = mid+1;
while (p1<=mid && p2<=high)
{
if(a[p1]>a[p2]){
resTarget += high - p2 +1;
++p1;
}
else
++p2;
}
return resTarget;
}
long long MergeSortAndCount(int a[],int low,int high,int tmp[]){
long long resTarget = 0;
if(low<high){
int mid = low + (high-low)/2;
resTarget += MergeSortAndCount(a,low,mid,tmp);
resTarget += MergeSortAndCount(a,mid+1,high,tmp);
resTarget += Count(a,low,mid,high);
Merge(a,low,mid,high,tmp);
}
return resTarget;
}
int main()
{
int n=3;
long long resSource,resTarget2; //Source和Target的逆序数
memset(a,0,sizeof(a)); memset(b,0,sizeof(b));
int ok=0,x;
//跳过0
for(int i=0;i<n*n;i++){
cin>>x;
if(x==0) ok=1;
else a[i-ok] = x;
}
resSource = MergeSortAndCount(a,0,n*n-2,b);
ok=0; memset(a,0,sizeof(a)); memset(b,0,sizeof(b));
//跳过0
for(int i=0;i<n*n;i++){
cin>>x;
if(x==0) ok=1;
else a[i-ok] = x;
}
resTarget2 = MergeSortAndCount(a,0,n*n-2,b);
if((resSource & 1) == (resTarget2 & 1))
cout<<"possible";
else
cout<<"impossible";
}