zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    LeetCode偶尔一题 —— 617. 合并二叉树
    《剑指offer》 —— 链表中倒数第k个节点
    《剑指offer》 —— 青蛙跳台阶问题
    《剑指offer》—— 二维数组中的查找
    《剑指offer》—— 替换空格
    《剑指offer》—— 合并两个排序的链表
    《剑指offer》—— 礼物的最大价值
    生成Nuget 源代码包来重用你的Asp.net MVC代码
    Pro ASP.Net Core MVC 6th 第四章
    Pro ASP.NET Core MVC 6th 第三章
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/5965050.html
Copyright © 2011-2022 走看看