今天状态不好,应该是没睡醒,先简写记录大致思路,具体细节过两天再补。
数码游戏即从左边网格布局通过0的上下左右移动交换,最终变为右边网格的状态,一般询问是否可达。
对于N*M的矩阵。
我们只需要考虑列数的奇偶性即可。当M为奇数时,逆序对数必须为偶数才可达;当M为偶数时,逆序对数必须与0
所在位置保持相同的奇偶性。
例题:
题目已经明确列数为偶数,所以需判断逆序对数与0相对最终位置距离奇偶性是否相同即可。逆序数个数可使用归并排序来统计。
#include <iostream>
using namespace std;
int ans=0;
void merge(int p[],int l,int mid,int r)
{
int t[r-l+1];
int p1=l,p2=mid+1;
int i=0;
while(p1<=mid&&p2<=r)//用数组t临时保存归并的两个小数组
{
if(p[p1]<p[p2])
{
t[i++]=p[p1++];
}
else
{
t[i++]=p[p2++];
ans+=(mid-p1+1);
}
//t[i++]=p[p1]<p[p2]?p[p1++]:p[p2++];
}
while(p1<=mid)
{
t[i++]=p[p1++];
}
while(p2<=r)
{
t[i++]=p[p2++];
}
for(int j=0;j<i;j++)
{
p[l+j]=t[j];
}
}
void mergesort(int p[],int l, int r)
{
if(l>=r)
return ;
int mid=(l+r)>>1;
mergesort(p,l,mid);
mergesort(p,mid+1,r);
merge(p,l,mid,r);
}
int main()
{
int T;
cin>>T;
while(T--)
{
ans=0;
int n=15;
int p[107];
int flag=0;
int o=1;
for(int i=1;i<=16;i++)
{
int d;
cin>>d;
if(d==0)
{
flag=4-i/4+(i%4!=0);
continue;
}
p[o++]=d;
}
mergesort(p,1,n);
if(ans%2==flag%2)
{
cout<<"Yes"<<endl;
}
else
cout<<"No"<<endl;
}
return 0;
}