zoukankan      html  css  js  c++  java
  • 双向广搜+hash+康托展开 codevs 1225 八数码难题

    codevs 1225 八数码难题

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 钻石 Diamond
     
    题目描述 Description

    Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
    问题描述

    在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

    输入描述 Input Description

    输入初试状态,一行九个数字,空格用0表示

    输出描述 Output Description

    只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

    样例输入 Sample Input

    283104765

    样例输出 Sample Output

    4

    数据范围及提示 Data Size & Hint

    详见试题

    分类标签 Tags 点此展开 

    启发式搜索 广度优先搜索 深度优先搜索 迭代搜索 搜索
    
    
      1 /*复杂题目模板加注解*/
      2 # include <stdio.h>
      3 # include <mem.h>
      4 
      5 # define MAXN (362880 + 5)
      6 
      7 typedef struct 
      8 {
      9     char a[9];
     10 }state;
     11 
     12 const int dir[4][2] = {{-1,0}, {0,1}, {1,0}, {0,-1}};
     13 int fact[9];
     14 
     15 int front, rear;
     16 state cur, nst;            /* new state */
     17 char vis[MAXN];
     18 char dist[MAXN];        /* 求的是最短距离( < 100),可以用 char 类型 */
     19 state Q[MAXN/2];
     20 
     21 
     22 void read(state *s);
     23 int inversions(state s);
     24 int cantor(state s);
     25 void init_fact(void);
     26 int bfs_d(state start, state goal);
     27 
     28 int main()
     29 {
     30     state start, goal;
     31     
     32     freopen("in.txt", "r", stdin);
     33     freopen("out.txt", "w", stdout);
     34     
     35     init_fact();
     36 
     37     read(&start);/*指针引用*/
     38     read(&goal);
     39 
     40     if (inversions(start)%2 == inversions(goal)%2)/
     41     {/*判断能不能到达最终状态,如果能达到最终状态的话,那么格子中的个数在后面有几个比他小的数的和的奇偶是不变的,无论怎么变换,可以用归纳推理证明*/
     42         printf("%d
    ", bfs_d(start, goal));
     43     }
     44     else puts("-1");/*找不到最终的状态*/
     45 
     46     return 0;
     47 }
     48 
     49 int bfs_d(state start, state goal)
     50 {
     51     int i, x, y, nx, ny, ct, nt;
     52 
     53     memset(vis, 0, sizeof(vis));
     54     memset(dist, 0, sizeof(dist));
     55 
     56     front = 1;
     57     Q[front] = start;
     58     rear = 2;
     59     Q[rear++] = goal;
     60     vis[cantor(start)] = 1;                /* 1 表示从起始节点扩展得到 */
     61     vis[cantor(goal)] = 2;                /* 2 表示从目标节点扩展得到 */
     62 
     63     while (front < rear)
     64     {
     65         cur = Q[front++];
     66         ct = cantor(cur);
     67         for (i = 0; cur.a[i] && i < 9; ++i);/*找出0的位置*/
     68         x = i / 3;/*求出0所在的行数列数*/
     69         y = i % 3;
     70         for (i = 0; i < 4; ++i)
     71         {
     72             nx = x + dir[i][0];/*把0向四周扩展*/
     73             ny = y + dir[i][1];
     74             if (nx>=0 && nx<3 && ny>=0 && ny<3)
     75             {
     76                 nst = cur;
     77                 nst.a[x*3+y] = cur.a[nx*3+ny];/*互换0的位置与对应元素的位置*/
     78                 nst.a[nx*3+ny] = 0;
     79                 if (!vis[nt = cantor(nst)])/*判断当前这个状态是否已经到过*/
     80                 {
     81                     Q[rear++] = nst;
     82                     /* foot[nt] = ct; */
     83                     dist[nt] = dist[ct] + 1;
     84                     vis[nt] = vis[ct];/*转移扩展的方向*/
     85                 }
     86                 else if (vis[ct] != vis[nt])/*如果已经到过,就是两者变换的次数和加上最后一次变化*/
     87                 {/*这是双向广搜的精髓,判断两个点是从不同的方向转移来的*/
     88                     return 1 + dist[nt] + dist[ct];
     89                 }
     90             }
     91         }
     92     }
     93 
     94     return -1;
     95 }
     96 
     97 void read(state *s)
     98 {
     99     int i;
    100     char c[5];
    101 
    102     for (i = 0; i < 9; ++i)
    103     {
    104         scanf("%s", c);
    105         if (c[0] == 'x') (*s).a[i] = 0;
    106         else (*s).a[i] = c[0] - '0';
    107     }
    108 }
    109 
    110 int inversions(state s)
    111 {
    112     char ch;
    113     int i, j, ret;
    114 
    115     ret = 0;
    116     for (i = 0; i < 9; ++i)
    117     {
    118         if (s.a[i] == 0) continue;
    119         ch = s.a[i];
    120         for (j = i+1; j < 9; ++j)
    121         {
    122             if (s.a[j] < ch && s.a[j] != 0)
    123                 ++ret;
    124         }
    125     }
    126 
    127     return ret;
    128 }
    129 
    130 int cantor(state s)/*康托展开应用于哈希表,处理排列问题是不会有冲突的,网上有证明,可以自己看*/
    131 {
    132     char ch;
    133     int i, j, ret, cnt;
    134 
    135     ret = 0;
    136     for (i = 0; i < 9; ++i)
    137     {
    138         cnt = 0;
    139         ch = s.a[i];
    140         for (j = i+1; j < 9; ++j)
    141         {
    142             if (s.a[j] < ch)
    143                 ++cnt;
    144         }
    145         ret += cnt*fact[8-i];
    146     }
    147 
    148     return ret;
    149 }
    150 
    151 void init_fact(void)
    152 {
    153     int i;
    154 
    155     fact[0] = 1;
    156     for (i = 1; i < 9; ++i)
    157     {
    158         fact[i] = i * fact[i-1];/*处理阶乘,整张图一共有9!种状态*/
    159     }
    160 }
    
    
    
     

    本题题解:

     1 #define N 3628800
     2 #include<iostream>
     3 #include<queue>
     4 #include<cstdio>
     5 #include<cstring>
     6 using namespace std;
     7 struct state{
     8     char a[10];
     9 }; 
    10 queue<state>que;
    11 int xx[]={0,0,1,-1};
    12 int yy[]={1,-1,0,0};
    13 int visit[N]={0};
    14 int fact[10]={0};
    15 int dis[N]={0};
    16 void init_goal(state& goal)
    17 {
    18     goal.a[0]='1';goal.a[1]='2';goal.a[2]='3';
    19     goal.a[3]='8';goal.a[4]='0';goal.a[5]='4';
    20     goal.a[6]='7';goal.a[7]='6';goal.a[8]='5';
    21     //goal.a="123804765";
    22     //strcpy(goal.a,"123804765");
    23 }
    24 void in_fact()
    25 {
    26     fact[0]=1;
    27     for(int i=1;i<9;++i)
    28       fact[i]=i*fact[i-1];
    29 }
    30 int cantor(state k)
    31 {
    32     int ret=0;
    33     for(int i=0;i<9;++i)
    34     {
    35         int cnt=0;
    36         char ch=k.a[i];
    37         for(int j=i+1;j<9;++j)
    38           if(ch>k.a[j]) cnt++;
    39         ret+=cnt*fact[8-i];
    40     }
    41     return ret;
    42 }
    43 int bfs(state begin,state goal)
    44 {
    45     que.push(begin);que.push(goal);
    46     int k1=cantor(begin);
    47     int k2=cantor(goal);
    48     visit[k1]=1;
    49     visit[k2]=2;
    50     dis[k1]=0;dis[k2]=0;
    51     while(!que.empty())
    52     {
    53         state fro=que.front();
    54         int can_fro=cantor(fro);
    55         que.pop();
    56         int i;
    57         for(i=0;fro.a[i]!='0'&&i<9;++i);
    58         int x=i/3;
    59         int y=i%3;
    60         for(int j=0;j<4;++j)
    61         {
    62             int nx=x+xx[j],ny=y+yy[j];
    63             if(nx>=0&&nx<3&&ny>=0&&ny<3)
    64             {
    65                 state now=fro;
    66                 now.a[3*x+y]=fro.a[3*nx+ny];
    67                 now.a[3*nx+ny]='0';
    68                 int kj=cantor(now);
    69                 if(!visit[kj])
    70                 {
    71                     que.push(now);
    72                     visit[kj]=visit[can_fro];/*转移是正向扩展还是逆向扩展*/
    73                     dis[kj]=dis[can_fro]+1;
    74                 }
    75                 else if(visit[kj]!=visit[can_fro])
    76                 {/*这是双向广搜的精髓,必须用visit表示当前这个是同时由正反广搜扩展来的*/
    77                     return 1+dis[kj]+dis[can_fro];
    78                 }
    79             }
    80         }
    81     }
    82 }
    83 int main()
    84 {
    85     state goal,begin;
    86     init_goal(goal);
    87     in_fact();
    88 //    scanf("%s",goal.a+1);
    89     scanf("%s",begin.a);
    90     printf("%d
    ",bfs(begin,goal));
    91     return 0;
    92 }
  • 相关阅读:
    Notification的使用
    Spring面向切面之AOP深入探讨
    使用注解配置Spring框架自动代理通知
    回顾Spring框架
    Spring利器之包扫描器
    Spring 核心概念以及入门教程
    Struts 2之动态方法调用,不会的赶紧来
    Struts2之过滤器和拦截器的区别
    Struts 2开讲了!!!
    Mybatis开篇以及配置教程
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5574877.html
Copyright © 2011-2022 走看看