zoukankan      html  css  js  c++  java
  • Hdu1401-Solitaire(双向bfs)

    Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left to right respectively.
    There are four identical pieces on the board. In one move it is allowed to:
    > move a piece to an empty neighboring field (up, down, left or right),
    > jump over one neighboring piece to an empty field (up, down, left or right).
    There are 4 moves allowed for each piece in the configuration shown above. As an example let's consider a piece placed in the row 4, column 4. It can be moved one row up, two rows down, one column left or two columns right.
    Write a program that:
    > reads two chessboard configurations from the standard input,
    > verifies whether the second one is reachable from the first one in at most 8 moves,
    > writes the result to the standard output.
     
    Input
    Each of two input lines contains 8 integers a1, a2, ..., a8 separated by single spaces and describes one configuration of pieces on the chessboard. Integers a2j-1 and a2j (1 <= j <= 4) describe the position of one piece - the row number and the column number respectively. Process to the end of file.
     
    Output
    The output should contain one word for each test case - YES if a configuration described in the second input line is reachable from the configuration described in the first input line in at most 8 moves, or one word NO otherwise.
     
    Sample Input
    4 4 4 5 5 4 6 5
    2 4 3 3 3 6 4 6
     
    Sample Output
    YES
     
    题意:棋盘大小为8*8,然后有4个球,给出初始所有球的位置以及目标位置,每次可以移动一个球,要么移动到旁边空的地方,要么跨过一个
    球到空的地方(不能跨过多个球),问能否在8步以内到达目标状态。
     
    解析:限定了8步,而且前后搜效果是一样的,所以可以考虑用双向bfs,然后8个数哈希,要注意对4个点要排序。
     
    代码
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int mod=500007;
    const int maxn=200005;
    int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
    bool in(int x,int y){ return x>=1&&x<=8&&y>=1&&y<=8; }
    struct point   //球的坐标
    {
        int x,y;
        point(int x=0,int y=0):x(x),y(y){}
        bool operator < (const point& t) const
        {
            if(x!=t.x) return x<t.x;
            return y<t.y;
        }
    };
    struct node
    {
        point p[4];  //每个节点保存4个球的坐标,并且是排好序的
    }nod[2][maxn];   //开二维用于双向搜
    struct Hash
    {
        int v,k,nid,next;   //保存哈希值,0或1,下标,next指针
    }ha[mod+maxn];
    int f[2],r[2],hash_id;  //队首队尾指针
    bool Same(int k1,int a,int k2,int b)  //判断两个结构体是否完全相同
    {
        for(int i=0;i<4;i++)
        {
            if(nod[k1][a].p[i].x!=nod[k2][b].p[i].x) return false;
            if(nod[k1][a].p[i].y!=nod[k2][b].p[i].y) return false;
        }
        return true;
    }
    int GetHash(point p[])  //得到哈希值
    {
        int ret=0,k=1;
        for(int i=0;i<4;i++)
        {
            ret+=p[i].x*k; k*=3;  //k是系数
            ret+=p[i].y*k; k*=3;
        }
        return ret;
    }
    int Insert_Hash(int v,int k,int nid)  //插入
    {
        int a=v%mod;
        int p=ha[a].next;
        while(p!=-1)
        {
            if(ha[p].v==v&&Same(ha[p].k,ha[p].nid,k,nid)) return ha[p].k==k?0:1;  //有相同的状态,k值相同返回0,不同返回1
            p=ha[p].next;
        }
        p=++hash_id;
        ha[p].v=v; ha[p].k=k; ha[p].nid=nid;  //增加新的节点
        ha[p].next=ha[a].next; ha[a].next=p;
        return -1;   
    }
    bool Has(node& t,int x,int y)
    {
        for(int i=0;i<4;i++) if(t.p[i].x==x&&t.p[i].y==y) return true;  //此处是球
        return false;
    }
    bool AddNode(node& t,int i,int j,int k)
    {
        int x=t.p[i].x;
        int y=t.p[i].y;
        int nx=x+dx[j];
        int ny=y+dy[j];
        if(!in(nx,ny)) return false;   //出界
        if(Has(t,nx,ny)) nx+=dx[j],ny+=dy[j]; //有球
        if(!in(nx,ny)) return false;  //出界
        if(Has(t,nx,ny)) return false; //还有球
        node& tt=nod[k][r[k]];
        tt=t;
        tt.p[i].x=nx; tt.p[i].y=ny;
        sort(tt.p,tt.p+4);   //排序
        int a=Insert_Hash(GetHash(tt.p),k,r[k]);
        if(a==1) return true;  //找到解
        else if(a==-1) r[k]++;  //增加新节点
        return false;  
    }
    bool bfs(int k)
    {
        int en=r[k];
        while(f[k]<en)
        {
            node& t=nod[k][f[k]++];
            for(int i=0;i<4;i++)   //4个球4个方向
                for(int j=0;j<4;j++) if(AddNode(t,i,j,k)) return true;
        }
        return false;
    }
    bool solve()
    {
        if(Same(0,0,1,0)) return true;  //相同
        int step=0;
        f[0]=f[1]=0; r[0]=r[1]=1;
        for(int i=0;i<mod;i++) ha[i].next=-1;
        hash_id=mod-1;
        Insert_Hash(GetHash(nod[0][0].p),0,0);
        Insert_Hash(GetHash(nod[1][0].p),1,0);
        while(f[0]<r[0]||f[1]<r[1])
        {
            if(step>=4) return false;
            step++;
            if(bfs(0)) return true;
            if(bfs(1)) return true;
        }
        return false;
    }
    int main()
    {
        int x,y;
        while(scanf("%d%d",&x,&y)!=EOF)
        {
            nod[0][0].p[0]=point(x,y);
            for(int i=1;i<4;i++)
            {
                 scanf("%d%d",&x,&y);
                 nod[0][0].p[i]=point(x,y);
            }
            for(int i=0;i<4;i++)
            {
                 scanf("%d%d",&x,&y);
                 nod[1][0].p[i]=point(x,y);
            }
            sort(nod[0][0].p,nod[0][0].p+4);
            sort(nod[1][0].p,nod[1][0].p+4);
            if(solve()) printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    mysql中drop、delete、truncate的区别简述
    hadoop之数据倾斜
    Mysql相关:navicat for mysql 加注释
    泛型
    工银亚洲见证开户详细过程和攻略
    classpath:和classpath*:的区别
    单索引与唯一索引
    MySQL中SQL语句之反引号,单引号
    《集体智慧编程》学习笔记 第三章
    《集体智慧编程》 读书笔记 第二章
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/5661560.html
Copyright © 2011-2022 走看看