HDU 1401 Solitaire(双向搜索)

题目:LINK

题意: 在一个8×8的棋盘中,给定你4个棋子A,再给你4个棋子B,问你在8步之内能不能够从A位置移动到B位置;
规则:棋子能能上下左右移动,同时能跳过相邻的棋子到达相邻棋子的空地方;


如果直接搜索无论是bfs还是dfs都会TLE的,可以发现无论是从开始的棋盘搜索到最终的棋盘,还是从最终的棋盘搜索到开始的棋盘是一样的。

所以我们从开始的棋盘搜索4步,从最终的棋盘搜索4步,检测有没有相同的可以达到的状态。
我是用DFS写的,分别从初始态和最终态搜索,复杂度2*(16^4) ,为了记录是否可以到达某个棋盘,可以状态压缩4个点的坐标,一个8个数字,每个数字大小1~8(占3位),一共用24位.
当然也可以用BFS写

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1000000000
int  mm[9][9];
bool vis[1<<24];
int flag ;
const int n = 8,m = 8;
struct node
{
    pair<int, int > p[6];
};
int dir[4][2]= { 0, 1, 0, -1, 1, 0, -1, 0};
node S, T;
pair<int, int> test(pair<int, int> in, int adx, int ady)
{
    pair<int, int> ret;
    int nx = in.first + adx;
    int ny = in.second + ady;
    if(nx < 1 || nx > n || ny < 1 || ny > m) {
        ret.first = ret.second = -1;
        return ret;
    }
    if(mm[nx][ny] != 1) {
        ret.first = nx; ret.second = ny;
        return ret;
    }
    nx += adx;
    ny += ady;
    if(nx < 1 || nx > n || ny < 1 || ny > m) {
        ret.first = -1; ret.second = -1;
        return ret;
    }
    if(mm[nx][ny] != 1) {
        ret.first = nx; ret.second = ny;
        return ret;
    }
    ret.first = ret.second = -1;
    return ret;
}
int getsta(node in)
{
    int sta = 0;
    int xx , yy;
    for(int i = 1; i<=4; i++) {
        xx = in.p[i].first;
        yy = in.p[i].second;
        xx --; yy --;
        sta = (sta << 3) | xx;
        sta = (sta << 3) | yy;
    }
    return sta;
}
void dfs(int x, node now, int ff)
{
    if(flag) return ;
    node next = now;
    sort(next.p+1, next.p+5);
    int sta = getsta(next);
    if(!ff) vis[sta] = 1;
    else if(vis[sta]) {
        flag = 1; return ;
    }

    if(x > 4)  return ;
    memset(mm, 0, sizeof(mm));
    for(int i=1; i<=4; i++)  mm[now.p[i].first][now.p[i].second] = 1;
    for(int i=1; i<=4; i++) {
        for(int j = 0; j< 4; j++) {
            next = now;
            pair<int, int> tmp = test(now.p[i], dir[j][0], dir[j][1]);
            if(tmp.first == -1) continue;
            next.p[i] = tmp;
            dfs(x+1, next, ff);
        }
    }
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int tmp;
    while(scanf("%d", &tmp) != EOF) {
        S.p[1].first = tmp;
        scanf("%d", &S.p[1].second);
        for(int i=2; i<=4; i++) scanf("%d%d", &S.p[i].first, &S.p[i].second);
        for(int i=1; i<=4; i++) scanf("%d%d", &T.p[i].first, &T.p[i].second);
        memset(vis, 0,sizeof(vis));
        sort(S.p+1, S.p+1+4);
        sort(T.p+1, T.p+1+4);
        flag = 0;
        dfs(1, S, 0);
        dfs(1, T, 1);
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值