算法實踐:滑塊拼圖

滑塊拼圖

描述

問題變爲判定從初始局

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可否相互變換?

  1. 求兩個N×N矩陣S和T的逆序數 rS和rT(扣除空格後)

  2. 若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";
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章