• Eight(经典题,八数码)


    Eight

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 20993    Accepted Submission(s): 5634
    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

     

    //就是类似九宫格那个游戏,不过这里9个格子大小都相等

    //学了比较多的东西,才懂怎么做

    这里我用的的是 A*+逆序数剪枝+hash判重 做的

    A*其实也好理解,就是 bfs 升级版

    这个博客写的很详细  http://www.cppblog.com/mythit/archive/2009/04/19/80492.aspx

    因为,无论怎么移动,逆序数的奇偶性是不变的,所以用这个能剪枝

    最大的问题就是怎么判重了,最多不过 9!种情况么,362880 ,每种情况对应一个数字,用一个 vis[ ]就能判重了,然后hash 判重就好理解了

    还有许多方法,推荐一篇博客 http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 有兴趣可以看看

    A* + hash 判重 + 曼哈顿距离

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cmath>
      4 #include <cstdlib>
      5 #include <algorithm>
      6 #include <iostream>
      7 #include <queue>
      8 #include <map>
      9 #include <vector>
     10 using namespace std;
     11 
     12 const int maxn=4e5+10;// 400010 最多不超过这么多状态 362880
     13 const int hash_[9]={1,1,2,6,24,120,720,5040,40320};
     14 struct Node
     15 {
     16     int state[3][3];
     17     int x,y;
     18     int g,h;        //g代表已耗费,h代表估计耗费
     19     int hash_num;   //这个状态的 hash 值
     20     bool operator < (const Node PP) const
     21     {
     22         //return g+h > PP.g+PP.h;
     23         //1638ms
     24         return h==PP.h ? g>PP.g : h>PP.h;
     25         //686ms
     26     }
     27 }star,ans;
     28 
     29 int dx[4]={1,-1,0,0};
     30 int dy[4]={0,0,1,-1};
     31 char op_c[8]={"durl"};
     32 struct Node2
     33 {
     34     int pre_hash;
     35     char op;
     36 }p[maxn];
     37 int vis[maxn];
     38 
     39 
     40 int count_hash(Node p)//获得hash值,计算的是 0-8 排列的hash
     41 {
     42     int i,j,k,hash_num=0;
     43     for (i=0;i<9;i++)
     44     {
     45         k=0;
     46         for (j=0;j<i;j++)
     47         {
     48             if (p.state[j/3][j%3]>p.state[i/3][i%3])
     49                 k++;
     50         }
     51         hash_num+=k*hash_[i];
     52     }
     53     return hash_num;
     54 }
     55 
     56 int count_h(Node p)//注意位置,要细致
     57 {
     58     int i,all=0;
     59     for (i=0;i<9;i++)
     60     {
     61         int e=p.state[i/3][i%3];
     62         if (e)
     63         {
     64             e-=1;
     65             all+=abs(i/3-e/3)+abs(i%3-e%3);
     66         }
     67     }
     68     return all;
     69 }
     70 
     71 
     72 void print(int h)
     73 {
     74     if (p[h].pre_hash==-1) return;
     75     print(p[h].pre_hash);
     76     printf("%c",p[h].op);
     77 }
     78 
     79 void A_star()
     80 {
     81     int i;
     82 
     83     star.hash_num = count_hash(star);
     84     star.g=0;
     85     star.h=count_h(star);
     86 
     87     memset(vis,0,sizeof(vis));
     88     vis[star.hash_num]=1;
     89     p[star.hash_num].pre_hash=-1; //头节点
     90 
     91     priority_queue <Node> Q;
     92     Q.push(star);
     93 
     94     Node e,n;
     95     int xx,yy;
     96 
     97     if (star.hash_num==ans.hash_num)//这个不能丢
     98     {
     99         printf("
    ");
    100         return;
    101     }
    102     while (!Q.empty())
    103     {
    104         e=Q.top();
    105         Q.pop();
    106 
    107         for (i=0;i<4;i++)
    108         {
    109             xx=e.x+dx[i];
    110             yy=e.y+dy[i];
    111             if (xx<0||yy<0||xx>=3||yy>=3) continue;
    112 
    113             n=e;
    114             n.x=xx;
    115             n.y=yy;
    116             swap(n.state[xx][yy],n.state[e.x][e.y]);
    117             n.g++;
    118             n.h=count_h(n);
    119             n.hash_num=count_hash(n);
    120 
    121             if (vis[n.hash_num]) continue;
    122 
    123             p[n.hash_num].pre_hash=e.hash_num;  //记录这个状态的的父 hash
    124             p[n.hash_num].op=op_c[i];           //记录怎么由父hash移动来的
    125 
    126             vis[n.hash_num]=1;
    127             if (n.hash_num==ans.hash_num)//说明到了
    128             {
    129                 print(n.hash_num);
    130                 printf("
    ");
    131                 return;
    132             }
    133             Q.push(n);
    134         }
    135     }
    136 }
    137 
    138 int main()
    139 {
    140     char str[30];
    141     int i;
    142 
    143     for(i=0;i<9;i++)                    //终点
    144         ans.state[i/3][i%3]=(i+1)%9;
    145     ans.hash_num=count_hash(ans);       //终点
    146 
    147     while(gets(str))
    148     {
    149         int i;
    150         int len=strlen(str);
    151 
    152         int j=0;
    153         for(i=0,j=0;i<len;i++)
    154         {
    155             if(str[i]==' ')continue;
    156             if(str[i]=='x')
    157             {
    158                 star.state[j/3][j%3]=0;
    159                 star.x=j/3;
    160                 star.y=j%3;
    161             }
    162             else star.state[j/3][j%3]=str[i]-'0';
    163             j++;                         // j/3 记录行数
    164         }
    165 
    166         //判断逆序数
    167         int temp [9],k=0;
    168         for (i=0;i<9;i++)
    169             temp[i]=star.state[i/3][i%3];
    170         for (i=0;i<9;i++)
    171         {
    172             if (temp[i]==0) continue;
    173             for (int j=0;j<i;j++)
    174                 if (temp[j]>temp[i]) k++;
    175         }
    176         if (k%2)
    177             printf("unsolvable
    ");
    178         else
    179             A_star();
    180     }
    181     return 0;
    182 }
    183 
    184 /*//错在这,浪费我2小时,才找出来! == 竟然不报错,而且是全局变量,第一次也不会错!!!
    185 
    186         for (i=0,j=0;i<len;i++)
    187         {
    188             if (str[i]==' ')continue;
    189             else if (str[i]=='x')
    190             {
    191                 star.x=j/3;
    192                 star.y=j%3;
    193                 star.state[j/3][j%3]==0;
    194             }
    195             else star.state[j/3][j%3]=str[i]-'0';
    196             j++;
    197         }
    198 */
    View Code

    IDA* + 曼哈顿距离 这个空间就省下来了,改一下,十五数码也能做的,上一个就不行了,内存爆炸

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <math.h>
      4 #include <stdlib.h>
      5 
      6 #define size 3          //这里规定几数码
      7 
      8 int move[4][2]={{-1,0},{0,-1},{0,1},{1,0}};//上 左 右 下  置换顺序
      9 char op[4]={'u','l','r','d'};
     10 
     11 int map[size][size],map2[size*size],limit,path[100];
     12 int flag,length;
     13 
     14 // 十五数码 的表
     15 //int goal[16][2]= {{size-1,size-1},{0,0},{0,1},{0,2},
     16 //                  {0,3},{1,0},{1,1},{1,2},
     17 //                  {1,3},{2,0},{2,1},{2,2},
     18 //                  {2,3},{3,0},{3,1},{3,2}};//各个数字应在位置对照表
     19 
     20 // 八数码 的表
     21 int goal[9][2]= {{size-1,size-1},{0,0},{0,1},{0,2},
     22                                  {1,0},{1,1},{1,2},
     23                                  {2,0},{2,1}};      //各个数字应在位置对照表
     24 
     25 int nixu(int a[size*size])
     26 {
     27     int i,j,ni,w,x,y;  //w代表0的位置 下标,x y 代表0的数组坐标
     28     ni=0;
     29     for(i=0;i<size*size;i++)  //,size*size=16
     30     {
     31         if(a[i]==0)  //找到0的位置
     32             continue;//w=i;
     33 
     34         for(j=i+1;j<size*size;j++)  //注意!!每一个都跟其后所有的比一圈 查找小于i的个数相加
     35         {
     36             if (a[j]==0)continue;
     37             if(a[i]>a[j])
     38                 ni++;
     39         }
     40     }
     41     //x=w/size;
     42     //y=w%size;
     43     //ni+=abs(x-(size-1))+abs(y-(size-1));  //最后加上0的偏移量
     44     if(ni%2==0)
     45         return 1;
     46     else
     47         return 0;
     48 }
     49 
     50 int hv(int a[][size])//估价函数,曼哈顿距离,小等于实际总步数
     51 {
     52     int i,j,cost=0;
     53     for(i=0;i<size;i++)
     54     {
     55         for(j=0;j<size;j++)
     56         {
     57             int w=map[i][j];
     58             cost+=abs(i-goal[w][0])+abs(j-goal[w][1]);
     59         }
     60     }
     61     return cost;
     62 }
     63 
     64 void swap(int*a,int*b)
     65 {
     66     int tmp;
     67     tmp=*a;
     68     *a=*b;
     69     *b=tmp;
     70 }
     71 
     72 void dfs(int sx,int sy,int len,int pre_move)//sx,sy是空格的位置
     73 {
     74     int i,nx,ny;
     75 
     76     if(flag)
     77         return;
     78 
     79     int dv=hv(map);
     80 
     81     if (len==limit)
     82     {
     83         if(dv==0)  //成功! 退出
     84         {
     85             flag=1;
     86             length=len;
     87             return;
     88         }
     89         else
     90             return;  //超过预设长度 回退
     91     }
     92     else if(len<limit)
     93     {
     94         if(dv==0)  //短于预设长度 成功!退出
     95         {
     96             flag=1;
     97             length=len;
     98             return;
     99         }
    100     }
    101 
    102     for(i=0;i<4;i++)
    103     {
    104         if(i+pre_move== 3&& len>0)//不和上一次移动方向相反,对第二步以后而言
    105             continue;
    106         nx=sx+move[i][0];  //移动的四步 上左右下
    107         ny=sy+move[i][1];
    108 
    109         if( 0<=nx && nx<size && 0<=ny && ny<size )  //判断移动合理
    110         {
    111             swap(&map[sx][sy],&map[nx][ny]);
    112             int p=hv(map);   //移动后的 曼哈顿距离p=16
    113 
    114             if(p+len<=limit&&!flag)  //p+len<=limit&&!flag剪枝判断语句
    115             {
    116                 path[len]=i;
    117                 dfs(nx,ny,len+1,i);  //如当前步成功则 递归调用dfs
    118                 if(flag)
    119                     return;
    120             }
    121             swap(&map[sx][sy],&map[nx][ny]);  //不合理则回退一步
    122         }
    123     }
    124 }
    125 
    126 int main()
    127 {
    128     int pp;
    129     int i,j,k,sx,sy;
    130     char str[30];
    131 
    132     while(gets(str))
    133     {
    134         int slen = strlen(str);
    135         j=0;
    136         for(i=0;i<slen;i++)
    137         {
    138             if (str[i]==' ')
    139                 continue;
    140             if (str[i]=='x')
    141                 map2[j]=0;
    142             else
    143                 map2[j]=str[i]-'0';
    144             j++;
    145         }
    146 
    147         for(i=0;i<size*size;i++)  //给map 和map2赋值map是二维数组,map2是一维数组
    148         {
    149             if(map2[i]==0)
    150             {
    151                 map[i/size][i%size]=0;
    152                 sx=i/size;
    153                 sy=i%size;
    154             }
    155             else
    156             {
    157                 map[i/size][i%size]=map2[i];
    158             }
    159         }
    160         flag=0,length=0;
    161         memset(path,-1,sizeof(path));  //已定义path[100]数组,将path填满-1
    162         if(nixu(map2)==1)                     //该状态可达
    163         {
    164             limit=hv(map);  //全部的曼哈顿距离之和
    165             while(!flag&&length<=50)//要求50步之内到达
    166             {
    167                 dfs(sx,sy,0,0);
    168                 if(!flag)
    169                 limit++; //得到的是最小步数
    170             }
    171             if(flag)
    172             {
    173                 for(i=0;i<length;i++)
    174                 printf("%c",op[path[i]]);  //根据path输出URLD路径
    175                 printf("
    ");
    176             }
    177         }
    178         else if(!nixu(map2)||!flag)
    179             printf("unsolvable
    ");
    180     }
    181     return 0;
    182 }
    View Code
  • 相关阅读:
    Android开发过程中遇到的问题集合(—)
    Android各种屏幕分辨率(VGA、HVGA、QVGA、WQVGA、WVGA、FWVGA) 具体解释
    Android中Context具体解释 ---- 你所不知道的Context
    HttpClient
    StretchDIBits使用方法
    int a[3];中a+1与&amp;a+1差别 -- C
    把质量控制工作往前推进(1)——安装sonarqube
    24点经典算法
    linux服务之udevd
    java实现第六届蓝桥杯星系炸弹
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/5965050.html
Copyright © 2020-2023  润新知