zoukankan      html  css  js  c++  java
  • hdu 1043 pku poj 1077 Eight (BFS + 康拓展开)

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

    http://poj.org/problem?id=1077

    Eight

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9173    Accepted Submission(s): 2473 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
     
    思路:
    八数码问题,我喜欢跟康拓展开联系在一起;
    这里解释下康拓展开:

    {1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个。123 132 213 231 312 321 。

    代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。

    他们间的对应关系可由康托展开来找到。

    如我想知道321是{1,2,3}中第几个大的数可以这样考虑 :

    第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,

    所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。 2*2!+1*1!+0*0!就是康托展开。

    再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,

    所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。

     
    先DFS从:
    1 2 3
    4 5 6  --->  到所有状态 都事先搜索出来 ,然后用 输入的状态 去中间 回溯查找 需要得到的状态 即可
    7 8 x
    AC代码:
    (提示POJ请用G++提交,用C++在POJ会超时的,我想了原因,可能是STL容器在C++中的耗时远大于G++)
      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <queue>
      4 #include <string.h>
      5 
      6 using namespace std;
      7 #define N 363000
      8 
      9 struct Nod
     10 {
     11     int b[10];
     12     int x,y,pos;
     13 }nd1,nd2;
     14 
     15 int fac[] = {1,1,2,6,24,120,720,5040,40320,362880};  //康拓展开用到的数组
     16  //康托展开:
     17 int cantor(int* a, int k)
     18 {
     19      int i, j, tmp, num = 0;
     20      for (i = 0; i < k; i++) {
     21          tmp = 0;
     22          for (j = i + 1; j < k; j++)
     23              if (a[j] < a[i])
     24                  tmp++;
     25          num += fac[k - i - 1] * tmp;
     26      }
     27      return num;
     28 }
     29 
     30 int mark[N],pre[N];
     31 char dir[N];
     32 int cx[]={0,0,1,-1};
     33 int cy[]={-1,1,0,0};
     34 
     35 void exchange(int *a,int x,int y)
     36 {
     37     int temp=a[x];
     38     a[x]=a[y];
     39     a[y]=temp;
     40 }
     41 
     42 void bfs(int *b,int x,int y)
     43 {
     44     queue<Nod> q;
     45     memset(mark,0,sizeof(mark));
     46     memset(pre,-1,sizeof(pre));
     47     nd1.x=x;
     48     nd1.y=y;
     49     memcpy(nd1.b,b,sizeof(int)*10);
     50     int i,temp;
     51     temp = cantor(b,9);
     52     mark[temp] = 1;
     53     nd1.pos = temp;
     54     q.push(nd1);
     55     while(!q.empty())
     56     {
     57         nd2 = q.front();
     58         q.pop();
     59         for(i=0;i<4;i++)
     60         {
     61             nd1.x = nd2.x + cx[i];
     62             nd1.y = nd2.y + cy[i];
     63             if(nd1.x>=0&&nd1.x<3&&nd1.y>=0&&nd1.y<3)
     64             {
     65                 memcpy(nd1.b,nd2.b,sizeof(int)*10);
     66                 exchange(nd1.b,nd1.x*3+nd1.y,nd2.x*3+nd2.y);
     67                 temp = cantor(nd1.b,9);
     68                 nd1.pos = temp;
     69                 if(mark[temp]==1)  continue;
     70                 mark[temp] = 1;
     71                 pre[temp] = nd2.pos;
     72                 if(cx[i]==0)
     73                 {
     74                     if(cy[i]==1)   dir[temp] = 'l';   //因为是从目标状态开始搜索的,最后需要倒序输出,然后方向也应该是相反输出
     75                     else    dir[temp] = 'r';    //dir[temp] = 'l' 的反方向
     76                 }
     77                 if(cy[i]==0)
     78                 {
     79                     if(cx[i]==1)   dir[temp] = 'u';  //同上
     80                     else    dir[temp] = 'd';  //同上
     81                 }
     82                 q.push(nd1);
     83             }
     84         }
     85     }
     86 }
     87 
     88 int main()
     89 {
     90     char str[5];
     91     int a[10],b[10]={1,2,3,4,5,6,7,8,9};  //末状态,从末状态开始搜索
     92     bfs(b,2,2);  //预先搜索所有状态
     93     while(~scanf("%s",str))
     94     {
     95         if(str[0]=='x')  a[0]=9;
     96         else a[0]=str[0]-'0';
     97         int i;
     98         for(i=1;i<9;i++)
     99         {
    100             scanf("%s",str);
    101             if(str[0]=='x')   a[i]=9;
    102             else    a[i]=str[0]-'0';
    103         }
    104         int temp = cantor(a,9);  //得到起始状态,然后回溯到末状态
    105         if(!mark[temp])  //所有状态里面若没有起始状态,则为不可达
    106         {
    107             printf("unsolvable
    ");
    108             continue;
    109         }
    110         while(temp)  //回溯过程
    111         {
    112             printf("%c",dir[temp]);
    113             temp = pre[temp];
    114         }
    115         putchar(10);
    116     }
    117     return 0;
    118 }
  • 相关阅读:
    生活希望[置顶] 程序员的奋斗史(十六)——谈习惯
    评论数据库Win A Free Copy of Packt’s Managing Multimedia and Unstructured Data in the Oracle Database ebook
    下载方法[jBPM5 部署] 最可靠,最简洁方式
    美感地方Python禅
    关系方向机缘之始
    截止账户[置顶] 国际黄金强势上涨投资者加油~~~~~~
    数据库书籍大师推荐的Oracle数据库相关的书籍,收集汇总。
    输出空格杨辉三角 (a+b)的n次幂的展开式中各项的系数很有规律,对于n=2,3,4时分别是:1 2 1, 1 3 3 1,1 4 6 4 1。这些系数构成了著名的杨辉三角形:
    错误删除Its not about the outage
    noncompatible bean definition of same name and class
  • 原文地址:https://www.cnblogs.com/crazyapple/p/3214558.html
Copyright © 2011-2022 走看看