hdu4021

24 Puzzle

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 785 Accepted Submission(s): 222

Problem Description

Daniel likes to play a special board game, called 24 puzzle. 24 puzzle is such a game that there are tiles with the number 1 to 23 in a play board like the follow picture:

C347-1001-1.jpg

The ‘#’ denotes the positions that the tiles may be placed on. There are 24 possible positions in total, so one of them is not occupied by the tile. We can denote the empty position by zero.
Daniel could move the tiles to the empty position if the tile is on the top, bottom, left or right of the empty position. In this way Daniel can reorder the tiles on the board.
Usually he plays with this game by setting up a target states initially, and then trying to do a series of moves to achieve the target. Soon he finds that not all target states could be achieved.
He asks for your help, to determine whether he has set up an impossible target or not.

Input

The first line of input contains an integer denoting the number of test cases.
For each test case, the first line contains 24 integers denoting the initial states of the game board. The numbers are the describing the tiles from top to bottom, left to right. And the empty position is indicated by zero. You can assume that the number of each tile are different, and there must be exactly one empty position. The second line of test case also contains 24 integers denoting the target states.

Output

For each test case, if the target is impossible to achieve, output ‘Y’ in a single line, otherwise, output ‘N’.

Sample Input

 
  

2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 3 1 2 0 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 3 0 2 1 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Sample Output

 
  

N Y

Source

The 36th ACM/ICPC Asia Regional Shanghai Site —— Online Contest

看完题目,最先可能会想到用BFS,但是面对,8数码问题中,为了表示棋局的状态,并为了方便的判重,采用了变进制数,但是此题若是采用变进制数,那么空间消耗可达到24!级别,远远超过了内存限制;就算放弃变进制数而改用其他的HASH,也会因为可能的棋局状态太多而爆空间,爆时间;

由于题目并没有要求输出由起始棋局到目标棋局的变化方案,只是要求判断“可达性”,所以联想到了8数码问题的两个状态之间的可达性判断;

关于数码类问题的可达性判断可以参照Blog:8-puzzled

由以上Blog中的相关结论,结合本题,最后得出以下结论:

两个状态可达性的充要条件:

(1)两个状态中突出来的8个顶点中的数值对应相等,(如果0在8个顶点中的某个,那么让它与相邻的4*4棋盘中的数交换位置),而且

(2)令两个状态的中间的4*4的棋盘中的对应的16个数的所形成的逆序对(除去空位0)分别为s1,s2,令两个状态中空位所在的行的差的绝对值为drow那么:

(1):s1与s2奇偶性相同,且drow为偶数

(2):s1与s2奇偶性不同,且drow为奇数

否则:两个状态不可达

以下是代码:

   1: #include<iostream>
   2: #include<cstdio>
   3: using namespace std;
   4:  
   5: int a[8],b[8],c[4][4],x[16];
   6: int reverse_order_num(int c[][4]){
   7:     int i,j,k;
   8:     k=0;
   9:     for (i=0;i<4;++i)
  10:         for (j=0;j<4;++j) x[k++]=c[i][j];
  11:     int tp=0;
  12:     for (i=0;i<15;++i) if (x[i])
  13:         for(j=i+1;j<16;++j) if (x[j]&&x[i]>x[j]) ++tp;
  14:     return tp;
  15: }
  16: #define xchange(x,y) (tp=x,x=y, y=tp)
  17: void find_zero(int* a,int c[][4],int& row){
  18:     int tp;
  19:     if (a[0]==0) xchange(a[0],c[0][0]);else
  20:         if (a[2]==0) xchange(a[2],c[0][0]);else
  21:             if (a[1]==0) xchange(a[1],c[0][3]);else
  22:                 if (a[3]==0) xchange(a[3],c[0][3]);else
  23:                     if (a[4]==0) xchange(a[4],c[3][0]);else
  24:                         if (a[6]==0) xchange(a[6],c[3][0]);else
  25:                             if (a[5]==0) xchange(a[5],c[3][3]);else
  26:                                 if (a[7]==0) xchange(a[7],c[3][3]);
  27:     int i,j;
  28:     for (i=0;i<4;++i)
  29:         for (j=0;j<4;++j) if (c[i][j]==0) row=i;
  30: }
  31: bool getdata_and_check(){
  32:     int s1=0,s2=0,row01,row02;
  33:     scanf("%d%d",&a[0],&a[1]);
  34:     int i;
  35:     scanf("%d",&a[2]); for (i=0;i<4;++i) scanf("%d",&c[0][i]); scanf("%d",&a[3]);
  36:     for (i=0;i<4;++i) scanf("%d",&c[1][i]);
  37:     for (i=0;i<4;++i) scanf("%d",&c[2][i]);
  38:     scanf("%d",&a[4]);for (i=0;i<4;++i) scanf("%d",&c[3][i]);scanf("%d",&a[5]);
  39:     scanf("%d",&a[6]);scanf("%d",&a[7]);
  40:     find_zero(a,c,row01);
  41:     s1=reverse_order_num(c)&1;
  42:     scanf("%d%d",&b[0],&b[1]);
  43:     scanf("%d",&b[2]); for (i=0;i<4;++i) scanf("%d",&c[0][i]); scanf("%d",&b[3]);
  44:     for (i=0;i<4;++i) scanf("%d",&c[1][i]);
  45:     for (i=0;i<4;++i) scanf("%d",&c[2][i]);
  46:     scanf("%d",&b[4]);for (i=0;i<4;++i) scanf("%d",&c[3][i]);scanf("%d",&b[5]);
  47:     scanf("%d",&b[6]);scanf("%d",&b[7]);
  48:     find_zero(b,c,row02);
  49:     s2=reverse_order_num(c)&1;
  50:     for (i=0;i<8;++i) if (a[i]!=b[i]) return false;
  51:     if (row02>row01) swap(row01,row02);
  52:     return (s1^s2)==((row01-row02)&1);
  53: }
  54: int main(){
  55:     int testnum;
  56:     scanf("%d",&testnum);
  57:     while (testnum--){
  58:         getdata_and_check()?puts("N"):puts("Y");
  59:     }
  60:     return 0;
  61: }

转载于:https://www.cnblogs.com/song19931218/archive/2011/09/21/2184207.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值