hdu 4021 24 Puzzle

4021  24 Puzzle

题目意思:给你一个如上图的图,格子从左到右从上到下编号,每个格子上有数字(0~23,0表示空),操作的过程为当一个格子的上下左右有空格子时可以交换两个格子的数字。

现在给你两个序列,表示的是对应编号上的数字,问能不能通过若干次操作将第一种序列变为第二个。

分析:首先考虑比较特殊的几个位置即最边上的格子,可以它们只能与一个格子交换所以先预处理一下,把能交换的交换,然后判一下两个序列这些位置上的数字是不是都相同,如果不想同那么最终不可以转化。那么剩下的就是4*4的方格了,其中有一个为空,就是15数码了。根据八数码判断能不能完成我们知道与当前状态的逆序数的奇偶有关。可以发现左右两个格子交换时是不改变逆序数的,只有上下交换时才会改变逆序数,无非是向前移动了n-1或相后移动n-1个位置(这里n=4),所以当n为奇数时上下交换逆序数的奇偶性不会改变,当n为偶数时则每一次上下交换,逆序数奇偶性改变。那么算法就出来了,计算一下两个序列对应的逆序数如果两个的逆序数奇偶性相同就可以转化否则不能。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include <cstring>
 4 #include <map>
 5 #include <algorithm>
 6 using namespace std;
 7 int a[30];
 8 int b[30];
 9 int mapa[20];
10 int mapb[20];
11 int pos[]=    {0, 1, 2, 7, 16, 21, 22, 23};
12 int swappos[]= {3, 6, 3, 6, 17, 20, 17, 20};
13 bool work()
14 {
15     for(int i=0; i<8; ++i)
16     {
17         if(a[pos[i]]==0)swap(a[pos[i]],a[swappos[i]]);
18         if(b[pos[i]]==0)swap(b[pos[i]],b[swappos[i]]);
19         if(a[pos[i]]!=b[pos[i]])return false;
20     }
21     int l=0;
22     for(int i=0; i<24; ++i)
23     {
24         int f=0;
25         for(int j=0; j<8; ++j)
26             if(i==pos[j])
27             {
28                 f=1;
29                 break;
30             }
31         if(f)continue;
32         mapa[l]=a[i];
33         mapb[l]=b[i];
34         l++;
35     }
36     int posa=-1,posb=-1;
37     int suma=0;
38     for(int i=1; i<16; ++i)
39     {
40         if(mapa[i]==0)
41         {
42             posa=i;
43             continue;
44         }
45         for(int j=0; j<i; ++j)
46             if(mapa[j]>mapa[i])suma++;
47     }
48     int sumb=0;
49     for(int i=1; i<16; ++i)
50     {
51         if(mapb[i]==0)
52         {
53             posb=i;
54             continue;
55         }
56         for(int j=0; j<i; ++j)
57             if(mapb[j]>mapb[i])sumb++;
58     }
59     int step = abs(posa/4 - posb/4);
60     step=abs(suma-sumb+step);
61     if(step&1)return false;
62     else return true;
63 }
64 int main ()
65 {
66     int t;
67     scanf("%d",&t);
68     while(t--)
69     {
70         for(int i=0; i<24; ++i)scanf("%d",&a[i]);
71         for(int i=0; i<24; ++i)scanf("%d",&b[i]);
72         if(work())printf("N\n");
73         else printf("Y\n");
74     }
75 }
View Code

 

转载于:https://www.cnblogs.com/shuzy/p/3511456.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值