HDU 1043 Eight 反向BFS

题意:同样的八数码问题。

思路:因为是多组测试,如果每次都来一遍bfs的话,一定会超时的。我们可以注意到,因为终点给定,我们可以反向求出其他状态到终点的路径。这个样子的话,判重只能用康拓展开了。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <set>

using namespace std;

typedef int state[9];

int dx[] = {0,0,-1,1};
int dy[] = {1,-1,0,0};
char dir[] = {'l','r','d','u'};
int fact[9];

const int MAX = 400000;

state que[MAX],en,st;
int fa[MAX],path[MAX],d[MAX];
bool vis[400000];
char str[50];

int cantor(state & t)
{
    int v = 0;
    for(int i = 0; i < 9; ++i){
        int cnt = 0;
        for(int j = i + 1; j < 9; ++j)
            if(t[j] < t[i]) cnt++;
        v += fact[8-i] * cnt;
    }
    return v;
}

bool insert(int v)
{
    if(vis[v]) return 0;
    return vis[v] = true;
}
void init()
{
    fact[0] = 1;
    for(int i = 1; i < 9; ++i)
        fact[i] = fact[i-1] * i;
    memset(fa,-1,sizeof(fa));
}

void bfs()
{
    int front = 0, tail = 0;
    memcpy(&que[tail],&st,sizeof(st)),tail++;
    while(front < tail){
        state & t = que[front];
        int vt = cantor(t);
        int z;
        for(z = 0; z < 9; ++z) if(!t[z]) break;
        int x = z / 3, y = z % 3;
        for(int i = 0; i < 4; ++i){
            int nx = x + dx[i], ny = y + dy[i];
            int nz = 3 * nx + ny;
            if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){
                state & s = que[tail];
                memcpy(&s,&t,sizeof(t));
                swap(s[z],s[nz]);
                int vs = cantor(s);
                if(insert(vs)){
                    fa[vs] = vt;
                    d[vs] = i;
                    tail++;
                }
            }
        }
        front++;
    }
}

int main(void)
{
    //freopen("input.txt","r",stdin);
    init();
    for(int i = 0; i < 8; ++i) st[i] = i+1;
    st[8] = 0;
    bfs();
    while(~scanf("%s",str)){
        if(!sscanf(str,"%d",&en[0])) en[0] = 0;
        for(int i = 1; i < 9; ++i){
            scanf("%s",str);
            if(!sscanf(str,"%d",&en[i]))
                en[i] = 0;
        }
        int v = cantor(en);
        if(fa[v] == -1)
            puts("unsolvable");
        else{
            for(;v != 46233; v = fa[v])
                putchar(dir[d[v]]);
            puts("");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值