zoukankan      html  css  js  c++  java
  • 【洛谷P1379】八数码难题(广搜、A*)

    八数码难题

    题目描述

     

    一.广搜:

    首先要考虑用什么存每一个状态

    显然每个状态都用一个矩阵存是很麻烦的。

    我们可以考虑将一个3*3的矩阵用一个字符串或long long 存。

    每次扩展时再转化为矩阵。

    另外一个问题是判重,对于已经搜过的状态,就不再扩展了。

    10^9次方的bool数组会爆空间

    可以考虑用hash

    或者STL的mapset

    //map   洛谷 8964ms 
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    using namespace std;
    map<long long ,long long> m;
    long long s,que[10000010],head=1,tail=1;
    long long c[4][4];
    long long zx[5]={0,0,0,1,-1},
              zy[5]={0,1,-1,0,0};
    int main()
    {
        scanf("%lld",&s);
        m[s]=0;
        que[head]=s;
        while(head<=tail)        //广搜 
        {
            int x,y;
            long long u=que[head++];    //取出队首元素 
            long long uu=u;
            if(u==123804765) break;
            for(int i=1;i<=3;i++)    //将long long型转化为矩阵 
             for(int j=1;j<=3;j++)
             {
                 c[i][j]=uu%10;
                 if(c[i][j]==0){        //标记空格 
                     x=i;
                     y=j;
                 }
                 uu/=10;
             }
            for(int i=1;i<=4;i++)
            {
                long long xx=x+zx[i],yy=y+zy[i];    //向四个方向搜索 
                if(1<=xx&&xx<=3&&1<=yy&&yy<=3)
                {
                    swap(c[x][y],c[xx][yy]);
                    long long l=0;
                    for(int j=3;j>=1;j--)
                     for(int k=3;k>=1;k--)
                      l=l*10+c[j][k];            //将扩展状态转化为长整形 
                    map < long long ,long long > :: iterator it = m.find(l) ;    //判重   map中的find函数用于寻找象所对应的原象(键值),若查找失败,返回最后一个键值位置 
                    if(it==m.end()){
                        m[l]=m[u]+1;
                        que[++tail]=l;
                    }
                    swap(c[x][y],c[xx][yy]);
                }
            }
        }
        printf("%lld
    ",m[123804765]);
        return 0;
    }
    //hash   洛谷 1080ms 
    #pragma GCC optimize(3)
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MOD=23333333;
    long long s,que[10000010],time[10000010],head=1,tail=1;
    long long c[4][4];
    long long zx[5]={0,0,0,1,-1},
              zy[5]={0,1,-1,0,0};
    bool hashnum[100000000];
    inline bool hash(long long s)
    {
        long long h=1,i=1;
        while(s)
        {
            i++;
            long long k=s%10;
            s/=10;
            h=(h*i*233+k)%MOD;
        }
        if(!hashnum[h]){
            hashnum[h]=1;
            return 1;
        }
        else return 0;
    }
    int main()
    {
        scanf("%lld",&s);
        que[head]=s;
        while(head<=tail)
        {
            int x,y;
            long long u=que[head++];
            long long uu=u;if(u==123804765) break;
            for(register int i=1;i<=3;i++)
             for(register int j=1;j<=3;j++)
             {
                 c[i][j]=uu%10;
                 if(c[i][j]==0){    
                     x=i;
                     y=j;
                 }
                 uu/=10;
             }
            for(register int i=1;i<=4;i++)
            {
                long long xx=x+zx[i],yy=y+zy[i];
                if(1<=xx&&xx<=3&&1<=yy&&yy<=3)
                {
                    swap(c[x][y],c[xx][yy]);
                    long long l=0;
                    for(int j=3;j>=1;j--)
                     for(int k=3;k>=1;k--)
                      l=l*10+c[j][k];
                    if(hash(l)){
                        que[++tail]=l;
                        time[tail]=time[head-1]+1;
                    }
                    swap(c[x][y],c[xx][yy]);
                }
            }
        }
        printf("%lld
    ",time[head-1]);
        return 0;
    }

    二、启发式搜索

     估价函数:

    close[i]=time[i]+cym[i]

    time[i]是搜到当前状态已经用的时间

    cym[i]表示每个数字到目标状态的曼哈顿距离之和/2

    可以看出,close[i]是小于实际步数的,所以搜起来效率高些

    //启发式搜索 420ms 
    #pragma GCC optimize(3)
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int MOD=23333333;
    long long s,num;
    long long data[10000010];
    int time[10000010];
    int close[10000010];
    struct cmp
    {
        bool operator()(int a,int b)
        {
            return close[a]>close[b];
        }
    };
    priority_queue<int,vector<int>,cmp> que;
    long long c[4][4];
    long long zx[5]={0,0,0,1,-1},
              zy[5]={0,1,-1,0,0};
    bool hashnum[100000000];
    inline bool hash(long long s)
    {
        long long h=1,i=1;
        while(s)
        {
            i++;
            long long k=s%10;
            s/=10;
            h=(h*i*233+k)%MOD;
        }
        if(!hashnum[h]){
            hashnum[h]=1;
            return 1;
        }
        else return 0;
    }
    int de[9][2]={{2,2},{1,1},{1,2},{1,3},{2,3},{3,3},{3,2},{3,1},{2,1}};
    inline int cym(long long tt)    //个位数字的笛卡尔距离之和 
    {
        int nn[4][4];
        for(register int i=0;i<3;i++)
             for(register int j=0;j<3;j++)
             {
                 nn[3-i][3-j]=tt%10;
                 tt/=10;
             }
        int mark=0;
        for(register int i=1;i<=3;i++)
         for(register int j=1;j<=3;j++)
             mark+=abs(i-de[nn[i][j]][0])+abs(j-de[nn[i][j]][1]);
        return mark>>1;
    }
    int main()
    {
        scanf("%lld",&s);
        data[++num]=s;
        close[num]=cym(s);
        que.push(num);
        int u;
        while(!que.empty())
        {
            int x,y;
            u=que.top();            //每次取估价最小的元素 
            que.pop();
            long long uu=data[u];if(uu==123804765) break;
            for(register int i=1;i<=3;i++)
             for(register int j=1;j<=3;j++)
             {
                 c[i][j]=uu%10;
                 if(c[i][j]==0){    
                     x=i;
                     y=j;
                 }
                 uu/=10;
             }
            for(register int i=1;i<=4;i++)
            {
                long long xx=x+zx[i],yy=y+zy[i];
                if(1<=xx&&xx<=3&&1<=yy&&yy<=3)
                {
                    swap(c[x][y],c[xx][yy]);
                    long long l=0;
                    for(int j=3;j>=1;j--)
                     for(int k=3;k>=1;k--)
                      l=l*10+c[j][k];
                     if(hash(l)){
                        data[++num]=l;
                        time[num]=time[u]+1;
                        close[num]=cym(l)+time[num];        //估价 
                        que.push(num);
                    }
                    swap(c[x][y],c[xx][yy]);
                }
            }
        }
        printf("%lld
    ",time[u]);
        return 0;
    }
  • 相关阅读:
    Latex文件如何拆分进行独立编译?
    梯度下降优化算法
    Google大脑科学家贾杨清(Caffe缔造者)-微信讲座
    Jeecg 如何执行批量insert或者update操作,高效率
    【JEECG_3.7.1】列表多表头的设计
    t:formvalid中定义callback函数
    Excel导入的时候日期格式会变成double式的String数据处理
    sql 跨表修改的方式
    js判断字符串str是否包含字符串substr
    帆软报表和jeecg的进一步整合--ajax给后台传递map类型的参数
  • 原文地址:https://www.cnblogs.com/yjkhhh/p/8636578.html
Copyright © 2011-2022 走看看