zoukankan      html  css  js  c++  java
  • poj 3131 双向搜索+hash判重

    题意:

    初始状态固定(朝上的全是W,空格位置输入给出),输入初始状态的空格位置,和最终状态朝上的位置,输出要多少步才能移动到,超过30步输出-1.

    简析:

    每一个格子有6种状态,分别是

    0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR (上前后 对应的颜色)

    由于只给出了终态朝上的颜色,其他的不知道,所以终态真正应该有256种,对于这个可以用一次dfs全部枚举出。

    一、

    搜索策略的问题

    单向搜索的话,平均一下,大概每次也有3个状态,30层的话,复杂度太高,放弃。

    A*的话,考虑当前不在正确位置的格子数。不知道是否可行,没有尝试。

    双向搜索的话,只有30层,平分一下15层,再看看时间5s,还是可以接受的。而考虑到最终状态有256个,所以反向扩展的速度非常快,所以我们可以让

    反向搜索只进行10层左右,保持2边平衡达到最佳速度。

    二、

    考虑判重的问题

    由上面的分析可知,判重可以选择2种方式。

    1、用一个6进制可以存下所有非空格的情况,再加一个空格的位置也就是6^8*9=15116544这么大的数组,双向搜索的话,也就是这个的2倍大的数组。

    2、用一个7进制存下所有情况7^9-1=40353607,双向搜索的话,就是2倍………接近1亿。

    第二种果断放弃了。。。

    三、

    hash值计算的问题

    显然初始情况的hash要 s[0]*6^0+s[1]*6^1+......,但如果以后每次我们都用一个for(0---9)的循环计算的话,时间复杂度太高。

    分析后发,每移动一次,左右移动的话,只会改变1个位置的值,上下移动的话只会改变3个位置的值,所以我们就计算这几个改变的值就够了。

    四、

    STL的使用,我测试了一下,不用STL的话速度可以快1000ms左右,但是内存就不好把握了,在上面都考虑到的情况下,用STL也不会影响AC。


    给出STL版本的

    include<cstdio>
    #include<cstring>
    #include<queue>
    #include<iostream>
    #include<algorithm>
    using namespace std;            // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR
    
    int base[]={1,6,36,216,1296,7776,46656,279936,1679616};
    int state[6][4]={{2,2,4,4},{5,5,3,3},{0,0,5,5},{4,4,1,1},{3,3,0,0},{1,1,2,2}};
    char hash1[1680000][9];
    char hash2[1680000][9];
    char b[10];
    struct node
    {
        int s[9];
        int dis;
        int space;
        int value;
    }st;
    queue<node> q;
    int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};      //下,上,右,左,和前面相反
    
    inline bool isok(int &x,int &y)
    {
        return x>=0&&x<3&&y>=0&&y<3;
    }
    inline int cal(node &t)     //计算初始的hash值
    {
        int value=0;
        int top=0;
        for(int i=0;i<9;i++)
        {
            if(i==t.space) continue;
            value+=t.s[i]*base[top++];
        }
        return value;
    }
     int cal(node &t,node &f,int d)     //因为每次移动只会改变几个hash值,所以可以特判
    {
        if(d==2)
        {
            t.value-=f.s[t.space]*base[f.space];
            t.value+=t.s[f.space]*base[f.space];
            return t.value;
        }
        else if(d==3)
        {
            t.value-=f.s[t.space]*base[t.space];
            t.value+=t.s[f.space]*base[t.space];
            return t.value;
        }
        else if(d==0)
        {
            for(int i=f.space;i<=f.space+2;i++)
            {
                t.value-=f.s[i+1]*base[i];
                t.value+=t.s[i]*base[i];
            }
            return t.value;
        }
        else if(d==1)
        {
            for(int i=t.space;i<=t.space+2;i++)
            {
                t.value-=f.s[i]*base[i];
                t.value+=t.s[i+1]*base[i];
            }
            return t.value;
        }
    }
    bool bfs(node st)
    {
        node t1,t2,f;
        queue<node> Q;
        st.dis=0;
        Q.push(st);
        t2.dis=0;
        int k;
        int k1=1,kk1=0,k2=256,kk2=0;
        while(!Q.empty()&&!q.empty())
        {
            while(k1--){
            st=Q.front();Q.pop();
            if(st.dis+1+t2.dis>30) {printf("-1
    ");return false;}
            for(int d=0;d<4;d++)
            {
                t1=st;
                int sx=t1.space/3;
                int sy=t1.space%3;
                int nx=sx+dir[d][0];
                int ny=sy+dir[d][1];
                if(isok(nx,ny))
                {
                    t1.space=nx*3+ny;
                    t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];
                    t1.s[nx*3+ny]=6;
                    t1.dis=st.dis+1;
                    t1.value=cal(t1,st,d);
                    if(hash1[t1.value][t1.space]) continue;
                    if(hash2[t1.value][t1.space]) {printf("%d
    ",t1.dis+t2.dis);return true;}
    
                    hash1[t1.value][t1.space]=t1.dis;
                    Q.push(t1);
                    kk1++;
                }
            }
            }
            k1=kk1;
            kk1=0;
            while(k2--){
            f=q.front();
            if(f.dis==9) break;
            q.pop();
            for(int d=0;d<4;d++)
            {
                t2=f;
                int sx=t2.space/3;
                int sy=t2.space%3;
                int nx=sx+dir[d][0];
                int ny=sy+dir[d][1];
                t2.dis=f.dis+1;
                if(isok(nx,ny))
                {
                    t2.space=nx*3+ny;
                    t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];
                    t2.s[nx*3+ny]=6;
                    t2.value=cal(t2,f,d);
                    if(hash2[t2.value][t2.space]) continue;
                    if(hash1[t2.value][t2.space])
                    {
                        printf("%d
    ",t2.dis+st.dis+1);
                        return true;
                    }
                    hash2[t2.value][t2.space]=t2.dis;
                    q.push(t2);
                    kk2++;
                }
            }
            }
            t1.dis=f.dis+1;
            k2=kk2;
            kk2=0;
        }
        printf("-1
    ");
    }
    void dfs(node &end,int k)
    {
        if(k==9)
        {
            end.dis=0;
            end.value=cal(end);
            q.push(end);
            hash2[end.value][end.space]=1;
            return;
        }
        if(b[k]=='W')
        {
            end.s[k]=0;
            dfs(end,k+1);
            end.s[k]=1;
            dfs(end,k+1);
        }
        else if(b[k]=='R')
        {
            end.s[k]=2;
            dfs(end,k+1);
            end.s[k]=3;
            dfs(end,k+1);
        }
        else if(b[k]=='B')
        {
            end.s[k]=4;
            dfs(end,k+1);
            end.s[k]=5;
            dfs(end,k+1);
        }
        else
        {
            end.s[k]=6;
            dfs(end,k+1);
        }
    }
    int main()
    {
        int x,y;
        char a;
        node end;
        while(scanf("%d%d",&y,&x)!=EOF)
        {
            if(!x&&!y) break;
            while(!q.empty()) q.pop();
            memset(hash1,0,sizeof(hash1));
            memset(hash2,0,sizeof(hash2));
    
            x--;y--;
            for(int i=0;i<9;i++)
            {
                if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}
                else st.s[i]=0;
            }
            for(int i=0;i<9;i++)
            {
                scanf(" %c",&a);
                if(a=='E') end.space=i;
                b[i]=a;
            }
            dfs(end,0);     //得到所有的终点状态,全部加入队列。
    
            int k;          //一开始就是答案
            st.value=cal(st);
            hash1[st.value][st.space]=-1;
            if(hash2[st.value][st.space]) {printf("0
    ");continue;}
            bfs(st);
        }
        return 0;
    }


    再给出静态数组版本

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;            // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR
    
    int base[]={1,6,36,216,1296,7776,46656,279936,1679616};
    int state[6][4]={{2,2,4,4},{5,5,3,3},{0,0,5,5},{4,4,1,1},{3,3,0,0},{1,1,2,2}};
    char hash1[1680000][9];
    char hash2[1680000][9];
    char b[10];
    struct node
    {
        int s[9];
        int dis;
        int space;
        int value;
    }q1[300000],q2[100005],st;
    int r2;
    int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};      //下,上,右,左,和前面相反
    
    inline bool isok(int &x,int &y)
    {
        return x>=0&&x<3&&y>=0&&y<3;
    }
    inline int cal(node &t)     //计算初始的hash值
    {
        int value=0;
        int top=0;
        for(int i=0;i<9;i++)
        {
            if(i==t.space) continue;
            value+=t.s[i]*base[top++];
        }
        return value;
    }
     int cal(node &t,node &f,int d)     //因为每次移动只会改变几个hash值,所以可以特判
    {
        if(d==2)
        {
            t.value-=f.s[t.space]*base[f.space];
            t.value+=t.s[f.space]*base[f.space];
            return t.value;
        }
        else if(d==3)
        {
            t.value-=f.s[t.space]*base[t.space];
            t.value+=t.s[f.space]*base[t.space];
            return t.value;
        }
        else if(d==0)
        {
            for(int i=f.space;i<=f.space+2;i++)
            {
                t.value-=f.s[i+1]*base[i];
                t.value+=t.s[i]*base[i];
            }
            return t.value;
        }
        else if(d==1)
        {
            for(int i=t.space;i<=t.space+2;i++)
            {
                t.value-=f.s[i]*base[i];
                t.value+=t.s[i+1]*base[i];
            }
            return t.value;
        }
    }
    bool bfs(node st)
    {
        node t1,t2,f;
        int r1=0,f1=0,f2=0;
        st.dis=0;
        q1[r1++]=st;
        t2.dis=0;
        int k;
        int k1=1,kk1=0,k2=256,kk2=0;
        while(f1<r1&&f2<r2)
        {
            while(k1--){
            st=q1[f1];
            if(st.dis+1+t2.dis>30) {printf("-1
    ");return false;}
            for(int d=0;d<4;d++)
            {
                t1=st;
                int sx=t1.space/3;
                int sy=t1.space%3;
                int nx=sx+dir[d][0];
                int ny=sy+dir[d][1];
                if(isok(nx,ny))
                {
                    t1.space=nx*3+ny;
                    t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];
                    t1.s[nx*3+ny]=6;
                    t1.dis=st.dis+1;
                    t1.value=cal(t1,st,d);
                    if(hash1[t1.value][t1.space]) continue;
                    if(hash2[t1.value][t1.space]) {printf("%d
    ",t1.dis+t2.dis);return true;}
    
                    hash1[t1.value][t1.space]=t1.dis;
                    q1[r1++]=t1;
                    kk1++;
                }
            }
            f1++;
            }
            k1=kk1;
            kk1=0;
            while(k2--){
            f=q2[f2];
            if(f.dis==8) break;         //超过这个,反向就不搜了,
            for(int d=0;d<4;d++)
            {
                t2=f;
                int sx=t2.space/3;
                int sy=t2.space%3;
                int nx=sx+dir[d][0];
                int ny=sy+dir[d][1];
                t2.dis=f.dis+1;
                if(isok(nx,ny))
                {
                    t2.space=nx*3+ny;
                    t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];
                    t2.s[nx*3+ny]=6;
                    t2.value=cal(t2,f,d);
                    if(hash2[t2.value][t2.space]) continue;
                    if(hash1[t2.value][t2.space])
                    {
                        printf("%d
    ",t2.dis+st.dis+1);
                        return true;
                    }
                    hash2[t2.value][t2.space]=t2.dis;
                    q2[r2++]=t2;
                    kk2++;
                }
            }
                f2++;
            }
    
            t1.dis=f.dis+1;
            k2=kk2;
            kk2=0;
        }
        printf("-1
    ");
    }
    void dfs(node &end,int k)
    {
        if(k==9)
        {
            end.dis=0;
            end.value=cal(end);
            q2[r2++]=end;
            hash2[end.value][end.space]=1;
            return;
        }
        if(b[k]=='W')
        {
            end.s[k]=0;
            dfs(end,k+1);
            end.s[k]=1;
            dfs(end,k+1);
        }
        else if(b[k]=='R')
        {
            end.s[k]=2;
            dfs(end,k+1);
            end.s[k]=3;
            dfs(end,k+1);
        }
        else if(b[k]=='B')
        {
            end.s[k]=4;
            dfs(end,k+1);
            end.s[k]=5;
            dfs(end,k+1);
        }
        else
        {
            end.s[k]=6;
            dfs(end,k+1);
        }
    }
    int main()
    {
        int x,y;
        char a;
        node end;
        while(scanf("%d%d",&y,&x)!=EOF)
        {
            if(!x&&!y) break;
            memset(hash1,0,sizeof(hash1));
            memset(hash2,0,sizeof(hash2));
            r2=0;
            x--;y--;
            for(int i=0;i<9;i++)
            {
                if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}
                else st.s[i]=0;
            }
            for(int i=0;i<9;i++)
            {
                scanf(" %c",&a);
                if(a=='E') end.space=i;
                b[i]=a;
            }
            dfs(end,0);     //得到所有的终点状态,全部加入队列。
    
            int k;          //一开始就是答案
            st.value=cal(st);
            hash1[st.value][st.space]=-1;
            if(hash2[st.value][st.space]) {printf("0
    ");continue;}
            bfs(st);
        }
        return 0;
    }



  • 相关阅读:
    hdu1251 && hud 1247 (字典树)
    linux系统调用kernel code
    Android init.rc 服务启动不成功
    android init执行service的脚本code位置
    printk %pS %pF含义
    进程页表图示
    linux内核之进程的基本概念(进程,进程组,会话关系)
    What is the purpose of the controlling terminal?
    android init.rc中service console option的含义、作用
    启动和停止init.rc中的服务
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3190053.html
Copyright © 2011-2022 走看看