HDU 1401 Solitaire (双向搜索)

每一步有4*4=16个决策,单向搜索的话有16^8种状态,双向搜索只有32^4种状态,缩小了解空间。


双向搜索用来解决起点和终点确定的搜索问题。方法就是从起点和终点轮流走,分别有各自的队列和标记数组。起点每到一个新的状态,就到终点的标记数组中查询,判断是否有交点。终点也是做一样的操作。


注意:Hash时如果像我一样8进制压缩,每个数必须是0~7的,也就是输入的坐标要减1


代码:

 

#include <iostream>
#include <cstdio>
#define LL long long
#include <cstring>
using namespace std;
#include <map>
#include <queue>
#include <algorithm>
struct node{
    int x,y;
};

node a[4];
node b[4];
bool visa[10][10];
bool visb[10][10];

int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};

bool cmp(node a,node b){
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}

LL Hash(node c[]){
    LL res=0;
    for(int i=0;i<4;i++){
        res=res*8+c[i].x;
        res=res*8+c[i].y;
    }
    return res;
}

void aHash(LL n,node a[]){
    for(int i=3;i>=0;i--){
        a[i].y=n%8;
        n/=8;
        a[i].x=n%8;
        n/=8;
    }
}

bool valid(int x,int y){
    if(x>=0&&x<8&&y>=0&&y<8) return 1;
    return 0;
}


bool bfs(){
    sort(a,a+4,cmp);
    sort(b,b+4,cmp);
    queue<LL> Qa;
    queue<LL> Qb;
    map<LL,int> at;
    map<LL,int> bt;
    LL cur1=Hash(a);
    Qa.push(cur1);
    at[cur1]=0;
    LL cur2=Hash(b);
    if(cur1==cur2) return 1;
    Qb.push(cur2);
    bt[cur2]=0;
    while(!Qa.empty()||!Qb.empty()){
        if(!Qa.empty()){
            LL cur=Qa.front(); Qa.pop();
            if(at[cur]<4){
                memset(visa,0,sizeof(visa));
                node k[4];
                node og[4];
                aHash(cur,og);
                for(int i=0;i<4;i++){
                    visa[og[i].x][og[i].y]=1;
                }
                for(int i=0;i<4;i++){
                    for(int j=0;j<4;j++){
                        for(int l=0;l<4;l++) k[l]=og[l];
                        int tx=k[i].x+dir[j][0];
                        int ty=k[i].y+dir[j][1];
                        if(!valid(tx,ty)) continue;
                        if(visa[tx][ty]){
                            tx+=dir[j][0];
                            ty+=dir[j][1];
                            if(!valid(tx,ty)||visa[tx][ty]) continue;
                        }
                        k[i].x=tx; k[i].y=ty;
                        sort(k,k+4,cmp);
                        LL nt=Hash(k);
                        if(at.count(nt)==0){
                            if(bt.count(nt)>0) return 1;
                            at[nt]=at[cur]+1;
                            Qa.push(nt);
                        }
                    }
                }
            }
        }
        if(!Qb.empty()){
            LL cur=Qb.front(); Qb.pop();
            if(bt[cur]<4){
                memset(visb,0,sizeof(visb));
                node k[4];
                node og[4];
                aHash(cur,og);
                for(int i=0;i<4;i++){
                    visb[og[i].x][og[i].y]=1;
                }
                for(int i=0;i<4;i++){
                    for(int j=0;j<4;j++){
                        for(int l=0;l<4;l++) k[l]=og[l];
                        int tx=k[i].x+dir[j][0];
                        int ty=k[i].y+dir[j][1];
                        if(!valid(tx,ty)) continue;
                        if(visb[tx][ty]){
                            tx+=dir[j][0];
                            ty+=dir[j][1];
                            if(!valid(tx,ty)||visb[tx][ty]) continue;
                        }
                        k[i].x=tx; k[i].y=ty;
                        sort(k,k+4,cmp);
                        LL nt=Hash(k);
                        if(bt.count(nt)==0){
                            if(at.count(nt)>0) return 1;
                            bt[nt]=bt[cur]+1;
                            Qb.push(nt);
                        }
                    }
                }
            }
        }
    }
    return 0;
}


int main(){
    while(~scanf("%d%d",&a[0].x,&a[0].y)){
        a[0].x--; a[0].y--;
        for(int i=1;i<4;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            x--; y--;
            a[i].x=x; a[i].y=y;
        }
        for(int i=0;i<4;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            x--; y--;
            b[i].x=x; b[i].y=y;
        }
        if(bfs()) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值