滑塊拼圖
描述
問題變爲判定從初始局
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";
}