• [luogu]P1379 八数码难题[广度优先搜索]


    八数码难题

    ——!x^n+y^n=z^n

      我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…)

      各位如果想用IDA*的可以看看这位大佬的这篇文章:

    http://www.cnblogs.com/ZYBGMZL/p/6852733.html

      接下来是我的方法,用luogu的跑了最慢是200ms,感觉还行把。

    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1

    283104765

    输出样例#1

    4

      因为这是要最优解且保证数据有解,于是就想到了BFS。

      然而这个过程是有许多障碍的,要怎样检验自己的状态是否为解,还有判重的操作,如果你没有判重,TLE即在眼前…

    所以我们可以想到压缩状态!当然如果用二进制难免有点力不从心,那我们干脆存成整数不就行了?但是可能你会发现,会有前导零的情况,怎么办?

    这时候其实可以在状态前加一个1,在int型中还是过得去的。

      那判重怎么搞?注意到这只有9!种状态。

      想到什么?康托尔展开!对于0~8的全排列,

      012345678 的字典序是1,如果让你手动操作我想没什么问题,那怎么让计算机做这件事?

      对于 (a(n-1) a(n-2)L a(0))的字典序计算方法为:

      Σ(ci*i!)ci为当前未出现的比ai小的数的个数。

      既然这样,我们就能把状态一一存下来了,交换的话很简单,读者手动操作即可发现规律。

      简单说明之后附上代码参考一下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define maxn 400000
    //阶乘?我当然打表啦。 
    int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};
    //状态 
    struct sjs{
        int num;
        int pos;
    }state[maxn];
    //队列 
    struct _757{
        int time;
        int now;
        int fd;
    }qu[maxn];
    int cto[9];
    //判重 
    bool rep[maxn];
    int head,tail;
    //特殊嗜好??? 
    namespace lys{
        //快速幂 
        int fpow(int p){
            int res=1,base=10;
            while(p>0){
                if(p&1) res*=base;
                base*=base;
                p>>=1;
            }
            return res;
        }
        //计算cantor 
        int cantor(int num){
            int i=0,pos,res=0;
            int x=num;
            memset(cto,0,sizeof cto);
            while(num>0){
                cto[i]=num%10;
                if(cto[i]==0) pos=i;
                num/=10;
                i++;
            }
            int j,cal;
            for(i=8;i>=0;i--){
                cal=0;
                for(j=8;j>i;j--){
                    if(cto[j]<cto[i]) cal++;
                }
                res+=(cto[i]-cal)*fac[i];
            }
            state[res+1].num=x;
            state[res+1].pos=pos;
            return res+1;
        }
        //判断是否能移动 
        bool chk(int pos,int i){
            switch(i){
                case 1:if(pos<6) return true ; return false ;
                case 2:if(pos>2) return true ; return false ;
                case 3:if(pos==8||pos==5||pos==2) return false ; return true ;
                case 4:if(pos==0||pos==3||pos==6) return false ; return true ;
            }
        }
        int bfs(){
            int t=0,i,st,ch,fp,x,num;
            do{
                st=qu[head].now;
                fp=fpow(state[st].pos);
                num=state[st].num;
                for(i=1;i<=4;i++){
                    if(chk(state[st].pos,i)){
                        switch(i){
                            case 1:
                                x=(num/(fp*1000))%10;
                                ch=num-x*fp*1000+x*fp;
                                x=cantor(ch);
                                qu[++tail].now=x;
                                qu[tail].time=(qu[head].time+1);
                                qu[tail].fd=head;
                                //目标态,觉得不这样写也行,直接用num比较 
                                if(x==46686){
                                    return qu[tail].time;
                                }
                                if(rep[x]) tail--;
                                else rep[x]=true ;
                                break ;
                            case 2:
                                x=(num/(fp/1000))%10;
                                ch=num-x*fp/1000+x*fp;
                                x=cantor(ch);
                                qu[++tail].now=x;
                                qu[tail].time=(qu[head].time+1);
                                qu[tail].fd=head;
                                if(x==46686){
                                    return qu[tail].time;
                                }
                                if(rep[x]) tail--;
                                else rep[x]=true ;
                                break ;
                            case 3:
                                x=(num/(fp*10))%10;
                                ch=num+x*fp-x*fp*10;
                                x=cantor(ch);
                                qu[++tail].now=x;
                                qu[tail].time=(qu[head].time+1);
                                qu[tail].fd=head;
                                if(x==46686){
                                    return qu[tail].time;
                                }
                                if(rep[x]) tail--;
                                else rep[x]=true ;
                                break ;
                            case 4:
                                x=(num/(fp/10))%10;
                                ch=num+x*fp-x*fp/10;
                                x=cantor(ch);
                                qu[++tail].now=x;
                                qu[tail].time=(qu[head].time+1);
                                qu[tail].fd=head;
                                if(x==46686){
                                    return qu[tail].time;
                                }
                                if(rep[x]) tail--;
                                else rep[x]=true ;
                                break ;
                        }
                    }        
                }
                head++;
            }while(head<=tail);
        }
        int main(){
            int i,j;
            char c;
            int st=0;
            for(i=1;i<=3;i++){
                for(j=1;j<=3;j++){
                    c=getchar();
                    while(c<'0'||c>'9') c=getchar();
                    st=st*10+c-'0';
                }
            }
            //初始状态 
            int r=cantor(1000000000+st);
            qu[++head].now=r;
            qu[head].time=0;
            rep[r]=true ;
            tail=1;
            printf("%d
    ",bfs());
            return 0;
        }
    }
    int main(){
        lys::main();
        return 0;
    }
  • 相关阅读:
    C#中的String.Length获取中文字符串长度出错
    PHP+Jquery+Ajax实现checkbox多选删除功能
    WIndows下AppAche服务中调试php页面出现警告:Call to undefined function mysql_connect()
    简洁的SQL一条语句更新从属账号
    算法导论数论一般离散对数问题
    Poj 2115
    算法导论数论计算x^2=1(mod n) 在区间[1,n1]的解
    算法导论数论RSA公钥加密系统
    算法导论数论中国余数定理
    Poj 2891 中国剩余定理 非互素
  • 原文地址:https://www.cnblogs.com/_inx/p/7228928.html
Copyright © 2020-2023  润新知