奇数码游戏是八数码问题的一个扩展,在一个n×n的网格中进行,其中n为奇数,1个空格和1~\(n^2-1\)这\(n^2-1\)个数恰好不重不漏地分布在n×n的网格中.空格移动的规则与八数码游戏相同,实际上,八数码就是一个n=3的奇数码游戏.现在给定两个奇数码游戏的局面,请判断是否存在一种移动空格的方式,使得其中一个局面可以变化到另一个局面。
分析:奇数码游戏两个局面可达,当且仅当两个局面下网格中的数依次写成1行\(n*n-1\)个元素的序列后(不考虑空格,也就是0),逆序对个数的奇偶性相同.证明请自行参考网上资料.所以我们只要求两次逆序对的个数,然后判断奇偶性是否相同就行了.
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=250005;
int ans1,ans2,a[N],b[N],c[N];
inline void msort1(int l,int r){
if(l==r)return;
int mid=(l+r)/2;
msort1(l,mid);msort1(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r){
if(a[i]<=a[j]){b[k]=a[i];k++;i++;}
else{
b[k]=a[j];k++;j++;
ans1+=mid-i+1;
}
}
while(i<=mid){b[k]=a[i];k++;i++;}
while(j<=r){b[k]=a[j];k++;j++;}
for(int i=l;i<=r;++i)a[i]=b[i];
}
inline void msort2(int l,int r){
if(l==r)return;
int mid=(l+r)/2;
msort2(l,mid);msort2(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r){
if(c[i]<=c[j]){b[k]=c[i];k++;i++;}
else{
b[k]=c[j];k++;j++;
ans2+=mid-i+1;
}
}
while(i<=mid){b[k]=c[i];k++;i++;}
while(j<=r){b[k]=c[j];k++;j++;}
for(int i=l;i<=r;++i)c[i]=b[i];
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
int tot1=0,tot2=0;
for(int i=1;i<=n*n;++i){
int x=read();
if(x)a[++tot1]=x;
}
for(int i=1;i<=n*n;++i){
int x=read();
if(x)c[++tot2]=x;
}
if(n==1){puts("TAK");continue;}
ans1=0;ans2=0;
msort1(1,tot1);msort2(1,tot2);
if(((ans1&1)&&(ans2&1))||(!(ans1&1)&&!(ans2&1)))puts("TAK");
else puts("NIE");
}
return 0;
}
本题是奇数码问题的拓展,网格变成\(n*m\),奇偶性不确定,且其中一个局面的逆序对个数为0.
我们只要求一个局面的逆序对个数,然后根据列数奇偶性分情况讨论:
1.若列数m为奇数,同上题,逆序对个数奇偶性相同即可,而其中一个局面已知逆序对个数为0,也就是偶数了.
2。若列数m为偶数,这次一个局面“逆序对个数+两个局面下空格之间的行数之差”与另一个局面的逆序对个数奇偶性相同即可.其中已知那个逆序对个数为0的局面的空格0在第n行.
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=1000005;
int ans,a[N],b[N];
inline void msort(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
msort(l,mid);msort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r){
if(a[i]<=a[j])b[k++]=a[i++];
else{
b[k++]=a[j++];
ans+=mid-i+1;
}
}
while(i<=mid)b[k++]=a[i++];
while(j<=r)b[k++]=a[j++];
for(int i=l;i<=r;++i)a[i]=b[i];
}
int main(){
while(1){
int n=read(),m=read();if(!n&&!m)break;
int tot=0,pos;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
int x=read();
if(x)a[++tot]=x;
else pos=i;
}
ans=0;msort(1,tot);
if(m&1){
if(ans&1)puts("NO");
else puts("YES");
}
else{
if((ans+n-pos)&1)puts("NO");
else puts("YES");
}
}
return 0;
}