hdu4021——N数码问题及其扩展

来源:互联网 发布:如何做好淘宝客推广 编辑:程序博客网 时间:2024/06/10 05:57

在一个N*N的矩阵里,填入0,1,2直到N*N-1,当一个数的上下左右四个方向中有一个方向的相邻的数为0时,该数就可以移动到相应位置。给定一个初始矩阵和一个目标矩阵。问能否通过上述操作,将初始矩阵变换为目标矩阵。

这类问题主要是从逆序数奇偶性的角度去考虑,将矩阵内的数按照从左往右从上往下的顺序写成一个数列(0除外),然后求出这个数列的逆序数(数对两数为降序排列的数对总数)。对于左右移操作,他们不改变逆序数,对于上下移操作,若N-1为偶数,不改变奇偶性,若为奇数则改变奇偶性。因此若N-1为偶数,只要目标矩阵与初始矩阵逆序数相同既可以实现变换。若N-1为奇数,则初始矩阵与目标矩阵中0的行数差(每移一行奇偶性变化一次)加初始逆序数若与目标逆序数同奇偶,则可以完成转换。

就这个题而言,还多了一步。由于八个角为死角,别的数移不进去,所以先将里面的零移出,如果这以后八个死角的值不相等则肯定不能完成转换。若想等,则转化为N数码问题(即上述)。

代码如下:

#include<cstdio>#include<cstring>#include<map>using namespace std;int Hash1[8]={0,1,2,7,16,21,22,23};map<int,int> Hash2;int S1[8],T1[16],S2[8],T2[16];void swap(int& a,int& b){    int c=a;a=b;b=c;}void read(int* a,int* b){    for(int i=0,j=0,k=0;i<24;++i){        if(Hash2.find(i)==Hash2.end()) scanf("%d",&b[j++]);        else scanf("%d",&a[k++]);    }}void deal(int *a,int* b){    for(int i=0;i<8;++i){        if(a[i]!=0) continue;        switch(i){            case 0:case 2:swap(a[i],b[0]);break;            case 1:case 3:swap(a[i],b[3]);break;            case 4:case 6:swap(a[i],b[12]);break;            case 5:case 7:swap(a[i],b[15]);break;        }    }}int main(){    Hash2[0]=0;Hash2[1]=1;Hash2[2]=2;Hash2[7]=3;    Hash2[16]=4;Hash2[21]=5;Hash2[22]=6;Hash2[23]=7;    int t,cnt1,cnt2,r1,r2;scanf("%d",&t);    bool flag;    while(t--){        flag=true;cnt1=cnt2=0;        read(S1,T1);read(S2,T2);        deal(S1,T1);deal(S2,T2);        for(int i=0;i<8;++i){            if(S1[i]!=S2[i]){flag=false;break;}        }        if(!flag){printf("Y\n");continue;}        for(int i=0;i<16;++i){            for(int j=i+1;j<16;++j){                if(T1[i]!=0&&T1[j]!=0&&T1[i]>T1[j]) ++cnt1;                if(T2[i]!=0&&T2[j]!=0&&T2[i]>T2[j]) ++cnt2;            }        }        for(int i=0;i<16;++i){            if(T1[i]==0) r1=i/4;            if(T2[i]==0) r2=i/4;        }        if((cnt1+cnt2+r1-r2)%2) printf("Y\n");        else printf("N\n");    }    return 0;}


0 0
原创粉丝点击