hdu 1043 eight a*


点击打开链接


题意: 八数码。给一个初始状态,然后让你还原回去,问最小步数,且打印路径。


题解: 直接bfs 超时,那就用A*, 哈曼顿距离f+g在队列中优先选择f+g最小的判断,能够加快广搜的搜索速度。标记用康托。

     另外,如果就像逆序数一样,如果来是和结尾的两个状态逆序数不同就不可能成功。否则可以。




#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <queue>
int a[10],f;
using namespace std;

struct node{
    int ma[3][3];
    int tx,ty;
    int hash_val;
    string way;
    int g,f;
    bool operator< (const node &a) const{
        return f>a.f;
    }
}ed,sta,e,u,q;
priority_queue<node>que;
int hash_tab[370000];
int fn[10]={1};
int ed_map[10][2];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
char w[]="drul";
bool judge(int x,int y){
    if(x<0||x>2||y<0||y>2) return 0;
    return 1;
}
void get_m(char st[]){
    int cnt=0,len=strlen(st);
    for(int i=0;i<len;++i){
        if(st[i]>'0'&&st[i]<='9') a[cnt++]=st[i]-'0';
        if(st[i]=='x') {
            a[cnt++]=0;
            sta.tx=(cnt-1)/3;
            sta.ty=(cnt-1)%3;
        }
    }
    cnt=0;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)
            ed.ma[i][j]=i*3+j+1,sta.ma[i][j]=a[cnt++];
    ed.ma[2][2]=0;
    for(int i=0;i<3;++i){
        for(int j=0;j<3;++j){
            sta.ma[i][j]=a[i*3+j];
            if(ed.ma[i][j]) ed_map[ed.ma[i][j]][0]=i,ed_map[ed.ma[i][j]][1]=j;
        }
    }
}

int get_hash(node aa){
    int ret=0,num=8,x;
    for(int i=0;i<3;++i){
        for(int j=0;j<3;++j){
            x=0;
            for(int k=j+1;k<3;++k)
                if(aa.ma[i][j]>aa.ma[i][k]) x++;
            for(int l=i+1;l<3;++l)
                for(int k=0;k<3;++k)
                    if(aa.ma[i][j]>aa.ma[l][k]) x++;
            ret+=fn[num]*x;
            num--;
        }
    }
    return ret;
}

int get_f(node a,int g){
    int h=0;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)
            if(a.ma[i][j]) h+=abs(i-ed_map[a.ma[i][j]][0])+abs(j-ed_map[a.ma[i][j]][1]);
    return g+h;
}
void exc(node &e,node b){
    swap(e.ma[e.tx][e.ty],e.ma[b.tx][b.ty]);
    e.hash_val=get_hash(e);
    e.g=b.g+1;
    e.f=get_f(e,e.g);
}
void bfs(){
    while(!que.empty()) que.pop();
    sta.hash_val=get_hash(sta);
    ed.hash_val=get_hash(ed);//cout<<sta.hash_val<<"  "<<ed.hash_val<<endl;
    sta.f=get_f(sta,0);
    sta.g=0;
    hash_tab[sta.hash_val]=1;
    que.push(sta);
    if(sta.hash_val!=ed.hash_val)
    while(!que.empty()){ //cout<<"@!@"<<endl;
        u=que.top();
        que.pop();
        for(int i=0;i<4;++i){
            int tx=u.tx+dir[i][0];
            int ty=u.ty+dir[i][1];
            if(judge(tx,ty)){
                e=u;
                e.tx=tx,e.ty=ty;
                exc(e,u);
                e.way+=w[i];
                if(hash_tab[e.hash_val]) continue;
                if(e.hash_val==ed.hash_val){
                    f=1; break;
                }
                que.push(e);
            }
        }
        if(f) break;
        hash_tab[u.hash_val]=1;
    }
    cout<<e.way<<endl;
}
int get_inv(node ss){
    int ret=0;
    for(int i=0;i<3;++i){
        for(int j=0;j<3;++j){
            if(!ss.ma[i][j]) continue;
            int sum=0;
            for(int k=j+1;k<3;++k)
                if(ss.ma[i][k]&&ss.ma[i][k]<ss.ma[i][j]) sum++;
            for(int l=i+1;l<3;++l)
                for(int k=0;k<3;++k)
                    if(ss.ma[l][k]&&ss.ma[l][k]<ss.ma[i][j]) sum++;
            ret+=sum;
        }
    }
    return ret%2;
}
int main(){
    char str[30];
    for(int i=1;i<9;++i) fn[i]=i*fn[i-1];
    while(gets(str)){
        f=0;memset(hash_tab,0,sizeof(hash_tab));
        get_m(str);
        if(get_inv(sta)^get_inv(ed)) puts("unsolvable");
        else  bfs();
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值