【八数码扩展】 奇数码问题

传送门

题意

八数码: 在一个$3\times $3的网格中给出\(1\sim 8\)的数字和一个空格,

5 2 8
1 3 _
4 6 7

空格可以和上下左右的数字进行交换,给定一个初始局面和终止局面,判断能否由初始局面转移到终止局面
奇数码为八数码的扩展,即\(n\times n\)阵,给定一个初始局面,一个最终局面,判断能否从初始局面到达最终局面。

数据范围

\(1\leq n < 500\)

题解

对于\(n\times m\) 的数码问题,将除了空格外的数字一次展成一行,初始局面序列为\(a_{i}\),最终局面序列为\(b_{i}\),结论如下:

  • \(m\)为奇数

    • \(a_{i}\)的逆序对数\(a\)的奇偶性与\(b_{i}\)的逆序对数\(b\)的奇偶性相同(不考虑\(0\)的逆序对),那么两个局面能够到达

    • \((a\& 1)==(b\& 1)\)

  • 如果\(m\)为偶数

    • \(a\)为初始序列的逆序对个数,\(b\)为终止,设\(c\)为两个序列中空格所在的行位置之差的绝对值

    • \(c\)为奇数,\(a\),\(b\)奇偶性不同,则两个局面可以互相到达

    • \(c\)为偶数的时候,\(a\)\(b\)奇偶性相同,两个局面可以互相到达,即\((a\& 1)==(b\& 1)^(c\& 1)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define fi first
#define se second 
#define ll long long
#define pb push_back
#define close ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);


typedef pair<long long,long long> pll;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<long long> vll;
typedef double db;


const ll mod=1e9+7;
const int N=510;

ll powmod(ll a,ll b,ll p)
{
    ll res=1;
    a%=p;
    while(b)
    {
        if(b&1) res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
ll gcd(ll a,ll b) 
{
    return b?gcd(b,a%b):a;
}


int _;
int n;
int a[N*N];
int b[N*N];
int ans[N*N];

int merge_sort(int a[],int l,int r)
{
    if(r-l<1)
        return 0;

    int mid=(l+r)>>1;

    int res=0;
    res+=merge_sort(a,l,mid);
    res+=merge_sort(a,mid+1,r);

    int k = 0,i = l,j = mid+1;
    while(i <= mid && j <= r)
    {
        if(a[i] <= a[j])
            ans[k++]=a[i++];
        else
        {
            ans[k++]=a[j++];
            res+=mid-i+1;
        }
    }

    while(i <= mid)
        ans[k++] = a[i++];
    while(j <= r)
        ans[k++] = a[j++];

    for(int i = l,j = 0; i <= r; i++,j++)
        a[i]=ans[j];
    return res;
}

void solve()
{
    while(cin>>n) 
    {
        int ok=0,x;
        for(int i = 1;i <= n*n;i++)
        {
            cin>>x;
            if(x==0)
                ok=1;
            else
                a[i-ok] = x;
        }
        ok=0;
        for(int i = 1;i <= n*n;i++)
        {
            cin>>x;
            if(x==0)
                ok=1;
            else
                b[i-ok] = x;
        }

        memset(ans,0,sizeof ans);
        int num1 = merge_sort(a, 1, n*n-1);
        memset(ans,0,sizeof ans);
        int num2 = merge_sort(b, 1, n*n-1);

        if((num1&1 ) == (num2&1) )
            cout<<"TAK"<<endl;
        else
            cout<<"NIE"<<endl;
    }
}
int main(){
    close;
    solve();
}
posted @ 2020-09-22 10:06  Hyx'  阅读(174)  评论(0编辑  收藏  举报