zoukankan      html  css  js  c++  java
  • 源哥每日一题第十六弹 八数码

    题目链接:

    hdu 1043:http://acm.hdu.edu.cn/showproblem.php?pid=1043
    poj 1077: http://poj.org/problem?id=1077

    题意:自己念第一次看到这个题,让我想到了小时候玩的华容道?或者是win7小程序里的那只巨嘴鸟?嗯嗯 大意就是给你个3*3的网格,在里面添上0~8 每次操作就是将0上下左右的数字和0交换,问你能不能变成123456780的状态,如果能,输出最小步数。

    题意很简单,思路也好想,广搜跑一下就好了。主要想的问题就是,怎么将状态存起来。相信经过之前的题目,大家应该有了一点想法,因为只有九位,完全可以应一个int就将一个状态存起来。但是这样还不是最有优秀的哈希方式,最优秀的方法自然是将9!个状态对应0~9!-1有没有这样的方法呢?当然有!

    康托展开完美的解决了这个问题。康托展开解决的问题很简单,就是建立某个排列和它所在位置的关系。

    详情请参考这篇博客:https://blog.csdn.net/fengyuzhicheng/article/details/79371008 这篇博客讲康托展开讲的非常好 没错,就是我

    有了这个理论的支撑,这个题的状态转移就好写了。只需要每次计算康托展开和逆变换,就可以很方便的进行搜索了。

    还有一个彩蛋,关于可行判断的。在讲线性代数的时候,我们学习到了一个很神奇的东西叫做逆序数(北大课件上的逆序数定义好像是不对的,查了很多关于逆序数的定义,都是计算在比当前数大的个数,不过对于这道题,无伤大雅,在这道题中,无论采用那种方法,即使计算的数可能不同,但奇偶排列的状况是一样的,而且从原理上讲,两种方式都可以)当逆序数是奇数时是奇排列,偶数就是偶排列,然后就是,在本题中,上下左右四种方法都不会改变排列的奇偶性(这个可以自己推一下)这样,在一开始就可以判断是否需要搜,也算是一种可行性剪枝吧。

    另外,这道题,我是写的双向广搜,单向广搜可能要超时

    #include <iostream>  
    #include <cstdio>  
    #include <cstring>  
    #include <algorithm>  
    #include <string>  
    #include <queue>  
      
    using namespace std;  
    char s[1000];  
    string ANS[2];  
    int f[10];  
    int a[10];  
    char z[2][10] = {"lrud","rldu"};  
    int dir[4] = {1,-1,3,-3};  
    int p_dir[4][9] = {  
        1,1,0,1,1,0,1,1,0,  
        0,1,1,0,1,1,0,1,1,  
        1,1,1,1,1,1,0,0,0,  
        0,0,0,1,1,1,1,1,1  
    };  
    struct Node {  
        int zero, status;  
        int s[9];  
        Node(){};  
        Node(int Z,int S){  
            zero = Z, status = S;  
        }  
    };  
    struct Path {  
        int fa; char c;  
        Path(){};  
        Path(int FA,int C) {  
            fa = FA, c = C;  
        }  
    };  
    Path path[400000];  
    queue<Node> q[2];  
    int jud[400000];  
      
    int Cantor(int a[]) {  
        int ans = 0;  
        for (int i = 0; i < 9; i++) {  
            int t = 0;  
            for (int j = 0; j < i; j++)  
                if (a[i]>a[j]) t++;  
                ans+=f[9-i-1]*(a[i]-1-t);  
        }  
        return ans;  
    }  
    int ca;  
    void dbfs(){  
        while (!q[0].empty()&&!q[1].empty()) {  
            for (int j = 0; j < 2; j++) {  
                for (int i = 0; i < 4; i++) {  
                    if (p_dir[i][q[j].front().zero]) {  
                        Node t = q[j].front();  
                        swap(t.s[t.zero],t.s[t.zero+dir[i]]);  
                        t.status = Cantor(t.s);  
                        if (!jud[t.status]) {  
                            path[t.status].fa = q[j].front().status;  
                            path[t.status].c = z[j][i];  
                            jud[t.status] = j+1;  
                            t.zero += dir[i];  
                            q[j].push(t);  
                        }  
                        else{  
                            if (jud[t.status]==2-j) {  
                                int t1 = q[j].front().status;   
                                int t2 = t.status;  
                                ANS[j]+=z[j][i];  
                                while (path[t1].fa!=-1) {  
                                    ANS[j]+=path[t1].c;  
                                    t1 = path[t1].fa;  
                                }  
                                while (path[t2].fa!=-1) {  
                                    ANS[1-j]+=path[t2].c;  
                                    t2 = path[t2].fa;  
                                }  
                                reverse(ANS[1].begin(),ANS[1].end());  
                                cout << ANS[1]<<ANS[0]<<endl;  
                                return;  
                            }  
                        }  
                    }  
                }  
                q[j].pop();   
            }     
        }  
        puts("unsolvable");  
    }  
    int check(int a[]) {  
        int ans = 0;  
        for (int i = 0; i < 9; i++) {  
            for (int j = 0; j < i; j++) {  
                if(a[i]<a[j]&&a[j]!=9) ans++;  
            }  
        }  
        return ans;  
    }  
    int main() {  
        f[0] = 1;  
        for (int i = 1; i < 10; i++) f[i] = f[i-1]*i;  
        while(cin.getline(s, 1000)) {  
            memset(path,0,sizeof(path));  
            memset(jud,0,sizeof(jud));  
            q[0] = q[1] = queue<Node>();  
            ANS[0].clear();ANS[1].clear();  
            int j = 0, t = 0;  
            for (int i = 0; i < strlen(s); ++i) {  
                if (s[i]<='8'&&s[i]>='1') {  
                    a[j++] = s[i]-'0';  
                }  
                else if (s[i]=='x'){  
                    a[j++] = 9;  
                    t = j-1;  
                }  
            }  
            if(check(a)%2) {  
                puts("unsolvable");  
                continue;  
            }  
            int ans = Cantor(a);  
            q[1].push(Node(t,ans));  
            q[0].push(Node(8,0));  
            for (int i = 0 ; i < 9; i++) {  
                q[0].front().s[i] = i+1;  
                q[1].front().s[i] = a[i];  
            }  
            path[0].fa = path[ans].fa= -1;  
            jud[0] = 1;  
            jud[ans] = 2;  
            dbfs();  
        }  
        return 0;  
    }  
    

      

  • 相关阅读:
    删除顺序表L中下标为p(0<=p<=length-1)的元素,成功返回1,不成功返回0,并将删除元素的值赋给e
    设顺序表中的数据元素递增有序,试着写一算法,将x插入到顺序表上的适当位置上,以保持该表的有序性。
    数据结构-顺序表基本操作的实现(含全部代码)【转】
    【转】结构体指针
    结构体(第十四章 )
    线性表
    第二章 c语言概述
    时间复杂度
    软件质量与测试 黑盒测试
    软件质量保证与测试 基本内容
  • 原文地址:https://www.cnblogs.com/fengyuzhicheng/p/9170594.html
Copyright © 2011-2022 走看看