內容來源《算法競賽進階指南》
date of submission:20191121
tags:歸排
description modelling:
你必定玩過八數碼遊戲,它其實是在一個3*3的網格中進行的,1個空格和1~8這8個數字剛好不重不漏地分佈在這3*3的網格中。
例如:
5 2 8
1 3 _
4 6 7
在遊戲過程當中,能夠把空格與其上、下、左、右四個方向之一的數字交換(若是存在)。
例如在上例中,空格可與左、上、下面的數字交換,分別變成:
5 2 8 5 2 _ 5 2 8
1 _ 3 1 3 8 1 3 7
4 6 7 4 6 7 4 6 _
奇數碼遊戲是它的一個擴展,在一個n*n的網格中進行,其中n爲奇數,1個空格和1~n*n-1這n*n-1個數剛好不重不漏地分佈在n*n的網格中。
空格移動的規則與八數碼遊戲相同,實際上,八數碼就是一個n=3的奇數碼遊戲。
如今給定兩個奇數碼遊戲的局面,請判斷是否存在一種移動空格的方式,使得其中一個局面能夠變化到另外一個局面。
輸入格式
多組數據,對於每組數據:
第1行一個整數n,n<500,n爲奇數。
接下來n行每行n個整數,表示第一個局面。
接下來n行每行n個整數,表示第二個局面。
局面中每一個整數都是0~n*n-1之一,其中用0表明空格,其他數值與奇數碼遊戲中的意義相同,保證這些整數的分佈不重不漏。
輸出格式
對於每組數據,若兩個局面可達,輸出TAK,不然輸出NIE。
major steps to solve it:
n數碼問題標準解法:
將n*n的矩陣依次寫成一行(空格除外)
n爲奇數(本題n都是奇數):只要兩個矩陣排成一行後逆序數奇偶性相等便可
n爲偶數:'逆序對數之差'和'兩個局面下空格所在行數之差'奇偶性相等
warnings:
AC code:
#include<cstdio>
using namespace std;
typedef long long ll;
ll a[500005];
ll tmp[500005];
ll num = 0;
void merge(ll left, ll mid, ll right)
{
ll i = left, j = mid + 1, n = left;
while (i <= mid && j <= right)
{
if (a[i] > a[j])
{
tmp[n++] = a[j++];
num += (j - n);
}
else
{
tmp[n++] = a[i++];
}
}
if (i > mid)
{
while (j <= right)
tmp[n++] = a[j++];
}
else
{
while (i <= mid)
tmp[n++] = a[i++];
}
for (ll k = left; k <= right; k++)
{
a[k] = tmp[k];
}
}
void mergesort(ll left, ll right)
{
if (left < right)
{
ll mid = (left + right) / 2;
mergesort(left, mid);
mergesort(mid + 1, right);
merge(left, mid, right);
}
}
int main()
{
//freopen("input.txt","r",stdin);
ll n;
while(~scanf("%lld",&n)&&n)
{
ll id=0;
for(ll i=0;i<n*n;i++)
{
ll x;
scanf("%lld",&x);
if(x) a[id++]=x;
}
num=0;
mergesort(0, id-1);
ll ans1=num;
id=0;
for(ll i=0;i<n*n;i++)
{
ll x;
scanf("%lld",&x);
if(x) a[id++]=x;
}
num=0;
mergesort(0, id-1);
ll ans2=num;
//cout<<ans1<<' '<<ans2<<endl;
if(ans1%2==ans2%2) printf("TAK\n");
else printf("NIE\n");
}
return 0;
}
算法