zoukankan      html  css  js  c++  java
  • HDU_1043 Eight 【逆向BFS + 康托展开 】【A* + 康托展开 】

    一、题目

    http://acm.hdu.edu.cn/showproblem.php?pid=1043

    二、两种方法

    该题很明显,是一个八数码的问题,就是9宫格,里面有一个空格,外加1~8的数字,任意一种情况,如果能通过移动空格使数码组成

    1 2 3
    4 5 6
    7 8 0 

    的形式,就输出变换的序列,如果不能,输出unsolvable.

    逆向$BFS$+康托展开

    1.什么是康托展开

    https://zh.wikipedia.org/wiki/%E5%BA%B7%E6%89%98%E5%B1%95%E5%BC%80

    $wiki$讲解比较好。

    有了康托展开,你可能会有疑问,要它有何用?但如果你联系一下$hash$函数,康托展开能够保证每一种八数码的情况都能够用一个整型数字唯一表示,这样是不是就好理解了?

    2.逆向BFS

    为了求出它的变换序列,我们可以逆向思维想一下,如果我从最终结果出发去变换,然后把路途中的每一种情况都记录下来(有了康托展开对八数码进行$hash$,会很方便),记录变换路径,然后对输入的其实条件直接进行输出就可以了。

    这就是逆向$BFS$的解决方案。

    这里需要注意的是,如果用STL的queue以及string,可能会造成超内存。解决办法就是用个数组模拟即可。

      1 #include <vector>
      2 #include <cstdio>
      3 #include <iostream>
      4 #include <fstream>
      5 #include <queue>
      6 #include <cstring>
      7 
      8 using namespace std;
      9 
     10 const int MAXN = 370000;
     11 const int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};    //factorial
     12 const int dx[] = {-1, 1, 0, 0};
     13 const int dy[] = {0, 0, 1, -1};
     14 const char op[] = "dulr";   //operation
     15 vector<char> Path[MAXN];          //记录路径
     16 bool Visit[MAXN];           //标记数组
     17 struct Node
     18 {
     19     int S[9];       //二维的数码表一维表示(下标从1开始)
     20     int loc;       //9 = x  loaction
     21     int cat;        //对应的康拓展开值
     22 };
     23 Node Q[MAXN];
     24 int Cantor(int s[])
     25 {
     26     int t, ans = 1;
     27     for(int i = 0; i < 9; i++)
     28     {
     29         t = 0;
     30         for(int j = i+1; j < 9; j++)
     31         {
     32             if(s[j] < s[i])
     33                 t++;
     34         }
     35         ans += t*fac[9-i-1];
     36     }
     37     return ans;
     38 }
     39 
     40 
     41 void BFS()
     42 {
     43     memset(Visit, 0, sizeof(Visit));
     44     int x, y, Cnt = 0, Rea = 0;
     45     Node cur, t;
     46     for(int i = 0; i < 8; i++)
     47         cur.S[i] = i+1;
     48     cur.S[8] = 0;
     49     cur.loc = 8;
     50     cur.cat = Cantor(cur.S);
     51     //Path[cur.cat] = "";
     52     Visit[cur.cat] = 1;
     53     Q[Cnt++] = cur;
     54     
     55     while(Rea < Cnt)
     56     {
     57         
     58         t = Q[Rea];
     59         Rea++;
     60         for(int i = 0; i < 4; i++)
     61         {
     62             x = t.loc/3 + dx[i];
     63             y = t.loc%3 + dy[i]; 
     64             if(x < 0 || x > 2 || y < 0 || y > 2)
     65                 continue;
     66             cur = t;                        //**
     67             cur.loc = x*3+y;
     68             cur.S[t.loc] = t.S[cur.loc];    //交换
     69             cur.S[cur.loc] = 0;             //X
     70             cur.cat = Cantor(cur.S);
     71             if(!Visit[cur.cat])
     72             {
     73                 Visit[cur.cat] = 1;
     74                 Path[cur.cat] = Path[t.cat];
     75                 Path[cur.cat].push_back(op[i]);
     76                 //Path[cur.cat] = op[i] + Path[t.cat];
     77                 Q[Cnt++] = cur;
     78 
     79             }
     80         }
     81     }
     82 }
     83 
     84 
     85 int main()
     86 {
     87     //freopen("input.txt", "r", stdin);
     88     //freopen("out.txt", "w", stdout);
     89     int s[10];
     90     char c[2];
     91     BFS();
     92 
     93 
     94     while(scanf("%s", c)!=EOF)
     95     {
     96         if(c[0] == 'x')
     97             s[0] = 0;
     98         else
     99             s[0] = c[0] - '0';
    100         for(int i = 1; i < 9; i++)
    101         {
    102             scanf("%s", c);
    103             if(c[0] == 'x')
    104                 s[i] = 0;
    105             else
    106                 s[i] = c[0] - '0';
    107         }
    108         int Cat = Cantor(s);
    109         if(Visit[Cat])
    110          {   
    111             for(int i = Path[Cat].size()-1; i >= 0; i--)
    112                 printf("%c", Path[Cat][i]);
    113             printf("
    ");
    114          }
    115         else
    116             printf("unsolvable
    ");//cout << "unsolvable" << endl;
    117     }
    118     return 0;
    119 }
    AC代码

    3.A*

    http://www.cnblogs.com/me-sa/archive/2010/05/18/A-Star-Pathfinding-for-Beginners.html

    基本A*算法的入门讲解都是这个。其实当你认真体会后,A*算法的关键就是F=G+H中的G,H如何算的问题,其他的与搜索大同小异,因为有了G,H,就可以有目的性的去搜索,也就是启发式搜索。(仅个人理解)

    这个题目里,求H依然采用的是曼哈顿距离,即每个每个数从当前位置到它最终位置的曼哈顿距离。

    这里,还用到了小技巧,就是逆序数,当在满足上述约定的八数码问题中,空格与相邻棋子的交换不会改变棋局中棋子数列的逆序数的奇偶性。因为最终情况的逆序数是偶数,所以要保证每次搜索过程中逆序数都是偶数。这样就达到了剪枝。

    需要注意的是,求逆序数,无论空格是代表的0还是9,都不要考虑进去。

    推广一下:对于N*M数码问题,空白在同一行交换不会导致奇偶性互变;上下行交换,如果列为奇数,则不会导致奇偶性互变;如果列数为偶数,则会导致奇偶性互变,所以此时还要考虑上下行交换的次数,综合得出答案。

      1 /*逆向BFS*/
      2 /*
      3 #include <vector>
      4 #include <cstdio>
      5 #include <iostream>
      6 #include <fstream>
      7 #include <queue>
      8 #include <cstring>
      9 
     10 using namespace std;
     11 
     12 const int MAXN = 370000;
     13 const int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};    //factorial
     14 const int dx[] = {-1, 1, 0, 0};
     15 const int dy[] = {0, 0, 1, -1};
     16 const char op[] = "dulr";   //operation
     17 vector<char> Path[MAXN];          //记录路径
     18 bool Visit[MAXN];           //标记数组
     19 struct Node
     20 {
     21     int S[9];       //二维的数码表一维表示(下标从1开始)
     22     int loc;       //9 = x  loaction
     23     int cat;        //对应的康拓展开值
     24 };
     25 Node Q[MAXN];
     26 int Cantor(int s[])
     27 {
     28     int t, ans = 1;
     29     for(int i = 0; i < 9; i++)
     30     {
     31         t = 0;
     32         for(int j = i+1; j < 9; j++)
     33         {
     34             if(s[j] < s[i])
     35                 t++;
     36         }
     37         ans += t*fac[9-i-1];
     38     }
     39     return ans;
     40 }
     41 
     42 
     43 void BFS()
     44 {
     45     memset(Visit, 0, sizeof(Visit));
     46     int x, y, Cnt = 0, Rea = 0;
     47     Node cur, t;
     48     for(int i = 0; i < 8; i++)
     49         cur.S[i] = i+1;
     50     cur.S[8] = 0;
     51     cur.loc = 8;
     52     cur.cat = Cantor(cur.S);
     53     //Path[cur.cat] = "";
     54     Visit[cur.cat] = 1;
     55     Q[Cnt++] = cur;
     56     
     57     while(Rea < Cnt)
     58     {
     59         
     60         t = Q[Rea];
     61         Rea++;
     62         for(int i = 0; i < 4; i++)
     63         {
     64             x = t.loc/3 + dx[i];
     65             y = t.loc%3 + dy[i]; 
     66             if(x < 0 || x > 2 || y < 0 || y > 2)
     67                 continue;
     68             cur = t;                        //**
     69             cur.loc = x*3+y;
     70             cur.S[t.loc] = t.S[cur.loc];    //交换
     71             cur.S[cur.loc] = 0;             //X
     72             cur.cat = Cantor(cur.S);
     73             if(!Visit[cur.cat])
     74             {
     75                 Visit[cur.cat] = 1;
     76                 Path[cur.cat] = Path[t.cat];
     77                 Path[cur.cat].push_back(op[i]);
     78                 //Path[cur.cat] = op[i] + Path[t.cat];
     79                 Q[Cnt++] = cur;
     80 
     81             }
     82         }
     83     }
     84 }
     85 
     86 
     87 int main()
     88 {
     89     //freopen("input.txt", "r", stdin);
     90     //freopen("out.txt", "w", stdout);
     91     int s[10];
     92     char c[2];
     93     BFS();
     94 
     95 
     96     while(scanf("%s", c)!=EOF)
     97     {
     98         if(c[0] == 'x')
     99             s[0] = 0;
    100         else
    101             s[0] = c[0] - '0';
    102         for(int i = 1; i < 9; i++)
    103         {
    104             scanf("%s", c);
    105             if(c[0] == 'x')
    106                 s[i] = 0;
    107             else
    108                 s[i] = c[0] - '0';
    109         }
    110         int Cat = Cantor(s);
    111         if(Visit[Cat])
    112          {   
    113             for(int i = Path[Cat].size()-1; i >= 0; i--)
    114                 printf("%c", Path[Cat][i]);
    115             printf("
    ");
    116          }
    117         else
    118             printf("unsolvable
    ");//cout << "unsolvable" << endl;
    119     }
    120     return 0;
    121 }
    122 2 3 4 1 5 0 7 6 8 
    123 2 3 0 1 5 4 7 6 8 
    124 90747
    125 2 3 4 1 5 0 7 6 8 
    126 92307
    127 
    128 */
    129 
    130 /* A* */
    131 
    132 #include <cstdio>
    133 #include <iostream>
    134 #include <cstring>
    135 #include <queue>
    136 #include <fstream>
    137 
    138 using namespace std;
    139 
    140 const int MAXN = 4000000;
    141 const int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};    //factorial
    142 const int dx[] = {0, 0, 1, -1};
    143 const int dy[] = {1, -1, 0, 0};
    144 const char op[] = "rldu";   //operation
    145 const int Aim = 46234;
    146 int Pre[MAXN];
    147 char Vp[MAXN];
    148 bool Visit[MAXN];
    149 struct Node
    150 {
    151     int s[9];
    152     int cat;
    153     int g, h;
    154     int loc;
    155 
    156     bool operator < (const Node &t)const
    157     {
    158         if(h == t.h)
    159             return g > t.g;
    160         return h > t.h;
    161     }
    162 };
    163 
    164 int getCator(const int s[])
    165 {
    166     int t, ans = 1;
    167     for(int i = 0; i < 9; i++)
    168     {
    169         t = 0;
    170         for(int j = i+1; j < 9; j++)
    171         {
    172             if(s[j] < s[i])
    173                 t++;
    174         }
    175         ans += t*fac[9-i-1];
    176     }
    177     return ans;
    178     
    179 }
    180 
    181 int getH(const int s[])
    182 {
    183     int x, y, x0, y0, ans = 0;
    184     for(int i = 0; i < 9; i++)
    185     {
    186         if(s[i])
    187         {
    188             x0 = i/3, y0 = i%3;
    189             x = (s[i]-1)/3, y = (s[i]-1)%3;     //这里要注意
    190             ans += abs(x-x0) + abs(y-y0);       //曼哈顿距离
    191         }
    192     }
    193     return ans;
    194 }
    195 
    196 bool judge(const int S[])       //判断逆序对数是否为偶数
    197 {
    198     int ans = 0;
    199     for(int i = 0; i < 9; i++)
    200     {
    201         for(int j = i+1; j < 9; j++)
    202         {
    203             if( S[j] && S[i] && S[j] < S[i] )
    204                 ans++;
    205         }
    206     }
    207     if(ans%2 == 0)
    208         return true;
    209     else 
    210         return false;
    211 }
    212 
    213 void astar(Node cur)
    214 {
    215     memset(Visit, 0, sizeof(Visit));
    216     memset(Pre, -1, sizeof(Pre));
    217     int x, y;
    218     priority_queue<Node> PQ;
    219     PQ.push(cur);
    220     Visit[cur.cat] = 1;
    221     Pre[cur.cat] = -1;
    222 
    223     while(!PQ.empty())
    224     {
    225         Node t = PQ.top();
    226         PQ.pop();
    227         for(int i = 0; i < 4; i++)
    228         {
    229             x = t.loc/3 + dx[i];
    230             y = t.loc%3 + dy[i];
    231             if(x < 0 || x > 2 || y < 0 || y > 2)
    232                 continue;
    233             cur = t;
    234             cur.loc = x*3 + y;
    235             cur.s[t.loc] = t.s[cur.loc];
    236             cur.s[cur.loc] = 0;
    237             cur.cat = getCator(cur.s);
    238 
    239             if(Visit[cur.cat] == 0 && judge(cur.s))
    240             {
    241 
    242                 Visit[cur.cat] = 1;
    243                 cur.h = getH(cur.s);
    244                 cur.g++;
    245                 Pre[cur.cat] = t.cat;
    246                 Vp[cur.cat] = op[i];
    247                 if(cur.cat == Aim)
    248                     return;
    249                 PQ.push(cur);
    250             }
    251         }
    252     }
    253 }
    254 
    255 void Print()
    256 {
    257     int c = Aim;
    258     string ans = "";
    259     while(Pre[c] != -1)
    260     {
    261         ans = Vp[c]+ans;
    262         c = Pre[c];
    263     }
    264     cout << ans << endl;
    265 }
    266 
    267 
    268 int main()
    269 {
    270     //freopen("input.txt", "r", stdin);
    271     //freopen("out.txt", "w", stdout);
    272     Node cur;
    273     char c[2];
    274     while(scanf("%s", c)!=EOF)
    275     {
    276         if(c[0] == 'x')
    277         {
    278             cur.s[0] = 0;
    279             cur.loc = 0;
    280         }
    281         else
    282             cur.s[0] = c[0] - '0';
    283         for(int i = 1; i < 9; i++)
    284         {
    285             scanf("%s", c);
    286             if(c[0] == 'x')
    287             {
    288                 cur.s[i] = 0;
    289                 cur.loc = i;
    290             }
    291             else
    292                 cur.s[i] = c[0] - '0';
    293         }
    294 
    295         if(!judge(cur.s))
    296         {
    297             printf("unsolvable
    ");
    298             continue;
    299         }
    300         cur.cat = getCator(cur.s);
    301         cur.g = 0, cur.h = getH(cur.s);
    302         astar(cur);
    303         Print();
    304     }
    305     return 0;
    306 }
    AC代码
  • 相关阅读:
    POJ1486 Sorting Slides 二分图or贪心
    POJ2060 Taxi Cab Scheme 最小路径覆盖
    POJ3083 Children of the Candy Corn 解题报告
    以前的文章
    POJ2449 Remmarguts' Date K短路经典题
    这一年的acm路
    POJ3014 Asteroids 最小点覆盖
    POJ2594 Treasure Exploration 最小路径覆盖
    POJ3009 Curling 2.0 解题报告
    POJ2226 Muddy Fields 最小点集覆盖
  • 原文地址:https://www.cnblogs.com/dybala21/p/10060777.html
Copyright © 2011-2022 走看看