zoukankan      html  css  js  c++  java
  • HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】

    本题有写法好几个写法,但主要思路是BFS:
    No。1
    采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重。如果只进行单向会超时。

    No。2
    采用hash进行判重,宽搜采用单向就可以AC。

    No。3
    运用康拓展开进行判重,即使采用单向宽搜时间效率也很高。

    哈希是想到了,但是我们应该选择什么哈希函数呢,看了网上一些神牛利用的是"康托展开",也就是利用全排列都有一个对应的整数,利用哈希函数把状态压缩成整数,这样就可以做到每一个整数都是唯一对应一个状态,那么这个时候就把哈希做完了。

    Eight
    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 29838    Accepted Submission(s): 7831
    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
     
    
    Source
    South Central USA 1998 (Sepcial Judge Module By JGShining)
     
    

    【代码】:

    #include<cstdio>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<cctype>
    #include<stack>
    #include<sstream>
    #include<list>
    #include<assert.h>
    #include<bitset>
    #include<numeric>
    #define debug() puts("+++++++++++++++++++++++++++++")
    #define gcd(a,b) __gcd(a,b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a,b,sizeof(a))
    #define sz size()
    #define be begin()
    #define pu push_up
    #define pd push_down
    #define cl clear()
    #define lowbit(x) -x&x
    #define all 1,n,1
    #define rep(i,x,n) for(int i=(x); i<(n); i++)
    #define in freopen("in.in","r",stdin)
    #define out freopen("out.out","w",stdout)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> P;
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e18;
    const int maxn = 1000000;
    const int maxm = 1e6 + 10;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int dx[] = {-1,1,0,0,1,1,-1,-1};
    const int dy[] = {0,0,1,-1,1,-1,1,-1};
    const int d[6][3]={ {0,0,1},{0,0,-1},{-1,0,0},{1,0,0},{0,1,0},{0,-1,0} };
    int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
    
    bool vis[maxn];
    
    int cantor(int *s) //康拖展开求该序列的hash值
    {
        int sum = 0;
        for(int i=0; i<9; i++)
        {
            int num = 0;
            for(int j=i+1; j<9; j++)
                if(s[j] < s[i]) num++;
            sum += (num*fac[9-i-1]);
        }
        return sum + 1;
    }
    
    struct node
    {
        int s[9]; //数位- 2  3  4  1  5  x-0  7  6  8
        int loc; //“0”的位置,把“x"当0
        int status; //康拖展开的hash值
        string path; //路径
    }st,ed,now;
    
    
    string path;
    
    int aim = 46234; //123456780对应的康拖展开的hash值
    
    char indexs[5]="udlr"; //正向搜索
    
    bool check(int tx,int ty)
    {
        return (tx<0||tx>2||ty<0||ty>2);
    }
    
    bool bfs()
    {
        ms(vis,0);
        queue<node> q;
        q.push(now);
        while(!q.empty())
        {
            st = q.front();
            q.pop();
            if(st.status==aim)
            {
                path = st.path;
                return true;
            }
            int x = st.loc/3;
            int y = st.loc%3;
            for(int i=0; i<4; i++)
            {
                //0和四周交换
                int tx = x + dir[i][0];
                int ty = y + dir[i][1];
                if(check(tx,ty)) continue;
                ed = st;
                ed.loc = tx * 3 + ty; //0和四周交换
                ed.s[st.loc] = ed.s[ed.loc];
                ed.s[ed.loc] = 0;
                ed.status = cantor(ed.s);
                if(!vis[ed.status])
                {
                    vis[ed.status] = true;
                    ed.path+=indexs[i];
                    if(ed.status==aim)
                    {
                        path=ed.path;
                        return true;
                    }
                    q.push(ed);
                }
            }
        }
        return false;
    }
    /*
    2  3  4  1  5  x  7  6  8
    ullddrurdllurdruldr
    */
    int main()
    {
        char ch;
        while(cin>>ch)
        {
            if(ch=='x') {now.s[0]=0; now.loc=0;}
            else now.s[0]=ch-'0';
            for(int i=1;i<9;i++)
            {
                cin>>ch;
                if(ch=='x')
                {
                    now.s[i]=0;
                    now.loc=i;
                }
                else now.s[i]=ch-'0';
            }
            now.status=cantor(now.s);//234150768——>
            if(bfs()) cout<<path<<endl;
            else cout<<"unsolvable"<<endl;
        }
    }
    
    

    //思路: 单向bfs()+哈希判重+路径输出(由于POJ数据只有一组,这个方法可以在POJ上面A,其它oj不能A )
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <cstdio>
    #include <cctype>
    #include <stack>
    #include <queue>
    #include <cmath>
    using namespace std;
    #define MAXN 400000
     
    struct State{
        int state[9];
        int pos;//空格位置
        char ch[50];//记录原始状态到达当前状态的路径(数组不能开太大不然超内存)
    }s[MAXN];//每一个状态对应一个结构体
    int  factor[9] = {1,1,2,6,24,120,720,5040,40320};//阶乘数组
    int  dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};//方向数组
    char dirtion[4] = {'u' , 'r' , 'd' , 'l'};
    int  vis[MAXN];//标记某个状态是否被走过
    int  start;//保存原始输入状态的哈希值
    State star;//原始状态对应的结构体
    queue<int>q;//这里不能直接放结构体,不然肯定超时
     
    //哈希映射
    int Hash(int s[]){
        int i , j , temp , num;
        num = 0 ;
        for(i = 0 ; i < 9 ; i++){
            temp = 0;
            for(j = i+1 ; j < 9 ; j++){
                if(s[j] < s[i]) temp++;
            }  
            num += factor[8-i]*temp;
        }
        return num;   
    }
     
    //广搜
    bool Bfs(){
        while(!q.empty()) q.pop();
        memset(vis , 0 , sizeof(vis));
        start = Hash(star.state);
        vis[start] = 1;
        s[start] = star;
        q.push(start);
        
        while(!q.empty()){
            State cur = s[q.front()];
            q.pop();
            
            int x , y , r , c;
            x = cur.pos/3 ; y = cur.pos%3;
            for(int i = 0 ; i < 4 ; i++){
                r = x+dir[i][0] ; c = y+dir[i][1];
                if(r < 0 || c < 0 || r >= 3 || c >= 3) continue;
                
                State tmp = cur;
                tmp.state[tmp.pos] = tmp.state[3*r+c];//原先空格位置换成新的编号
                tmp.pos = 3*r+c ; tmp.state[tmp.pos] = 9;//重新更新空格位置
                
                int hash = Hash(tmp.state);//求出当前哈希值
                if(vis[hash]) continue;
     
                vis[hash] = 1;
                int len = strlen(cur.ch);//求出前一个状态的路径长度
                tmp.ch[len] = dirtion[i];//更新路径
                s[hash] = tmp;//赋值
                if(hash == 0){//如果搜索到目标节点直接输出退出
                   printf("%s
    " , s[hash].ch) ; return 1;
                }          
                q.push(hash);//入对列
            }
        }
        return 0;
    }
     
    int main(){ 
        char c;
        while(scanf("%c" , &c) != EOF){
            if(c == 'x'){ star.state[0] = 9 ; star.pos = 0;}
            else star.state[0] = c-'0';
            for(int i = 1 ; i < 9 ; i++){
                scanf(" %c" , &c);
                if(c == 'x'){ star.pos = i ; star.state[i] = 9;}
                else star.state[i] = c-'0';
            }
            getchar();
            int flag = Bfs();
            if(!flag) printf("unsolvable
    ");//无解的情况
        }
        return 0;
    }
     
     
    
  • 相关阅读:
    【资源分享】一个匿名文件分享网站
    【C语言】指针到底有什么用
    【C语言】一招搞定C语言各种复杂指针
    【资源分享】Visual Studio全版本在线安装包(5MB)
    【资源分享】C语言也能干大事(第二版)
    【资源分享】迅雷
    Nuxt spa deploy
    nginx ssl docker
    Linux查看环境变量
    Nginx 配置
  • 原文地址:https://www.cnblogs.com/Roni-i/p/9311095.html
Copyright © 2011-2022 走看看