• HDU 1043 Eight (A* + HASH + 康托展开)


    Eight

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13956    Accepted Submission(s): 3957 Special Judge

    Problem Description
    The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
     1  2  3  4  5  6  7  8  9 10 11 12 13 14 15  x
    where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
     1  2  3  4     1  2  3  4     1  2  3  4     1  2  3  4  5  6  7  8     5  6  7  8     5  6  7  8     5  6  7  8  9  x 10 12     9 10  x 12     9 10 11 12     9 10 11 12 13 14 11 15    13 14 11 15    13 14  x 15    13 14 15  x             r->            d->            r->
    The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
    Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
    In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three arrangement.
     
    Input
    You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
    1  2  3 x  4  6 7  5  8
    is described by this list:
    1 2 3 x 4 6 7 5 8
     
    Output
    You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
     
    Sample Input
    2 3 4 1 5 x 7 6 8
     
    Sample Output
    ullddrurdllurdruldr
     
     
     
    这题活生生搞了五天,为此学了A*和康托展开,虽然自己写出来了但还不是非常明白,有句话说“如果你真的懂了那么你就应该自己动手做一个”,看来我还没真的懂。
    首先把每次矩阵的格局存结构里,然后对整个矩阵用康托展开来进行哈希,得到一个值,以此来判断此种情况是否出现过或是是否到达了终点,有一个很好的剪枝就是用奇偶逆序数来判断是否可解,因为最终情况的逆序数是0,而每次变换不会改变逆序数的奇偶,所以如果初始情况的逆序数是奇数的话就不可解。
    不明白的地方是A*的估值函数为何不用f = g + h,而是要用h和g分别作为两个参数来比较,刚开始的时候我把两个参数的位置弄反了, T了一天。都是泪。
      1 #include <iostream>
      2 #include <cmath>
      3 #include <string>
      4 #include <queue>
      5 #include <cstdio>
      6 #include <cstring>
      7 #include <algorithm>
      8 using    namespace    std;
      9 
     10 const    int    SIZE = 5;
     11 const    int    GOAL = 46233;
     12 const    int    HASH[] = {40320,5040,720,120,24,6,2,1,1};
     13 const    int    UP_DATE[][2] = {{0,-1},{0,1},{-1,0},{1,0}};
     14 int    PATH[600000];
     15 int    PRE[600000];
     16 struct    Node
     17 {
     18     int    map[SIZE][SIZE];
     19     int    x,y;
     20     int    h,g;
     21     int    hash;
     22     bool    operator <(const Node a) const
     23     {
     24         return    h != a.h ? h > a.h : g > a.g;
     25     }
     26 };
     27 
     28 bool    solve_able(const Node & r);
     29 bool    check(const int,const int);
     30 void    cal_hash(Node & r);
     31 void    cal_h(Node & r);
     32 void    search(const Node & r);
     33 void    show(void);
     34 int    main(void)
     35 {
     36     Node    first;
     37     char    s[50];
     38 
     39     while(gets(s))
     40     {
     41         int    k = 0;
     42         memset(PRE,-1,sizeof(PRE));
     43         memset(PATH,-1,sizeof(PATH));
     44         for(int i = 1;i <= 3;i ++)
     45             for(int j = 1;j <= 3;j ++)
     46             {
     47                 if(s[k] >= '1' && s[k] <= '9')
     48                     first.map[i][j] = s[k] - '0';
     49                 else    if(s[k] == 'x')
     50                 {
     51                     first.map[i][j] = 0;
     52                     first.x = i;
     53                     first.y = j;
     54                 }
     55                 else
     56                     j --;
     57                 k ++;
     58             }
     59         if(!solve_able(first))
     60         {
     61             printf("unsolvable
    ");
     62             continue;
     63         }
     64         cal_hash(first);
     65         if(first.hash == GOAL)
     66         {
     67             puts("");
     68             continue;
     69         }
     70         PATH[first.hash] = -2;
     71         first.g = 0;
     72         cal_h(first);
     73         search(first);
     74     }
     75 
     76     return    0;
     77 }
     78 
     79 bool    solve_able(const Node & r)
     80 {
     81     int    sum = 0,count = 0;
     82     int    temp[10];
     83 
     84     for(int i = 1;i <= 3;i ++)
     85         for(int j = 1;j <= 3;j ++)
     86         {
     87             temp[count] = r.map[i][j];
     88             count ++;
     89         }
     90     for(int i = 0;i < 9;i ++)
     91         for(int j = i + 1;j < 9;j ++)
     92             if(temp[j] < temp[i] && temp[j] && temp[i])
     93                 sum ++;
     94     return    !(sum & 1);
     95 }
     96 
     97 bool    check(const int    x,const    int y)
     98 {
     99     if(x >= 1 && x <= 3 && y >= 1 && y <= 3)
    100         return    true;
    101     return    false;
    102 }
    103 
    104 void    cal_hash(Node & r)
    105 {
    106     int    sum = 0,count = 0,box;
    107     int    temp[10];
    108 
    109     for(int i = 1;i <= 3;i ++)
    110         for(int j = 1;j <= 3;j ++)
    111         {
    112             temp[count] = r.map[i][j];
    113             count ++;
    114         }
    115     for(int i = 0;i < 9;i ++)
    116     {
    117         box = 0;
    118         for(int j = i + 1;j < 9;j ++)
    119             if(temp[j] < temp[i])
    120                 box ++;
    121         sum += (box * HASH[i]);
    122     }
    123     r.hash = sum;
    124 }
    125 
    126 void    search(Node const & r)
    127 {
    128     Node    cur,next;
    129 
    130     priority_queue<Node>    que;
    131     que.push(r);
    132     while(!que.empty())
    133     {
    134         cur = que.top();
    135         que.pop();
    136         for(int i = 0;i < 4;i ++)
    137         {
    138             next = cur;
    139             next.x = cur.x + UP_DATE[i][0];
    140             next.y = cur.y + UP_DATE[i][1];
    141             if(!check(next.x,next.y))
    142                 continue;
    143             swap(next.map[cur.x][cur.y],next.map[next.x][next.y]);
    144             cal_hash(next);
    145 
    146             if(PATH[next.hash] == -1)
    147             {
    148                 PATH[next.hash] = i;
    149                 PRE[next.hash] = cur.hash;
    150                 next.g ++;
    151                 cal_h(next);
    152                 que.push(next);
    153             }
    154             if(next.hash == GOAL)
    155             {
    156                 show();
    157                 return    ;
    158             }
    159         }
    160     }
    161 
    162 }
    163 
    164 void    cal_h(Node & r)
    165 {
    166     int    ans = 0;
    167     for(int i = 1;i <= 3;i ++)
    168         for(int j = 1;j <= 3;j ++)
    169             if(r.map[i][j])
    170                 ans += abs(i - ((r.map[i][j] - 1) / 3 + 1)) + abs(j - ((r.map[i][j] - 1) % 3 + 1));
    171     r.h = ans;
    172 }
    173 
    174 void    show(void)
    175 {
    176     string    ans;
    177     int    hash = GOAL;
    178 
    179     ans.clear();
    180     while(PRE[hash] != -1)
    181     {
    182         switch(PATH[hash])
    183         {
    184             case    0:ans += 'l';break;
    185             case    1:ans += 'r';break;
    186             case    2:ans += 'u';break;
    187             case    3:ans += 'd';break;
    188         }
    189         hash = PRE[hash];
    190     }
    191     for(int i = ans.size() - 1;i >= 0;i --)
    192         printf("%c",ans[i]);
    193     cout << endl;
    194 }
  • 相关阅读:
    Bubble Sort (5775)
    Dertouzos (5750)
    codeforces 360 E
    codeforces 360 D
    codeforces 360 C
    Mike and Cellphone
    训练2——B
    训练1——A
    符号三角形
    Sudoku Killer
  • 原文地址:https://www.cnblogs.com/xz816111/p/4366110.html
Copyright © 2020-2023  润新知