HDU 3567 八数码问题2 双BFS求解

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3567

主要练习双BFS的写法。只有一个注意点,见代码。手写了一个模拟队列,可惜时间根本没有提升,不知为啥,在HDU上提交时,得选C++,G++会TLE。


代码:

#include<iostream>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>
#define LL __int64
#define INF 0x7fffffff
using namespace std;

struct node{
    int s[9],n,cur,step;
}o,st,ed;

int fac[]={1,1,2,6,24,120,720,5040,40320};

int cantor(int *s){//康托展开
    int sum=0;
    for(int i=0;i<9;i++){
        int cnt=0;
        for(int j=i+1;j<9;j++)
            if(s[i]<s[j]) cnt++;
        sum+=(fac[9-i-1]*cnt);
    }
    return sum;
}

int d[][2]={1,0,0,-1,0,1,-1,0};
string dir="dlru";
int vis[2][363010];
string ans[363010];//存储路径,其实可以每个点只存储一个字符,但是没写出来,放弃了

void bfs(){
    memset(vis,0,sizeof(vis));
    for(int i=0;i<363000;i++) ans[i].clear();
    queue<node> Q[2];
    Q[0].push(st);Q[1].push(ed);
    vis[0][st.n]=vis[1][ed.n]=1;
    int deep=0;
    while(!Q[0].empty() || Q[1].empty()){
        int i=0;
        while(i<2){
            node tp=Q[i].front();
            if(tp.step!=deep) {i++;continue;}
            Q[i].pop();
            int x=tp.cur/3,y=tp.cur%3;
            for(int p=0;p<4;p++){
                int tx=x+d[p][0],ty=y+d[p][1];
                if(tx<0 || ty<0 || tx>=3 || ty>=3) continue;
                node tp2=tp;tp2.cur=tx*3+ty;tp2.step=tp.step+1;
                swap(tp2.s[tp.cur],tp2.s[tp2.cur]);
                tp2.n=cantor(tp2.s);
                if(!i && vis[1][tp2.n]){//为了保证最小字典序,只能i为0是才能输出
                    ans[tp.n]+=dir[p];
                    reverse(ans[tp2.n].begin(),ans[tp2.n].end());
                    cout<<(int)ans[tp.n].size()+(int)ans[tp2.n].size()<<endl;
                    cout<<ans[tp.n]<<ans[tp2.n]<<endl;return;
                }
                int k=i? 3-p:p;
                if(vis[1-i][tp2.n]) continue;
                if(!i && vis[i][tp2.n]) continue;
                //主要注意点就是下面这个if,对于反向搜索,需要判断新方向是否可以改变最小字典序
                if(i && vis[i][tp2.n] && ans[tp2.n][(int)ans[tp2.n].size()-1]<dir[k]) continue;
                ans[tp2.n]=ans[tp.n];ans[tp2.n]+=dir[k];
                Q[i].push(tp2);vis[i][tp2.n]=1;
            }
        }
        deep++;
    }
}


int main(){
    //freopen("D:\\in.txt","r",stdin);
    //freopen("D:\\out.txt","w",stdout);
    int T;cin>>T;
    for(int kase=1;kase<=T;kase++){
        char ch;
        for(int i=0;i<9;i++){
            cin>>ch;if(ch=='X') ch='0',st.cur=i;
            st.s[i]=ch-'0';
        }
        for(int i=0;i<9;i++){
            cin>>ch;if(ch=='X') ch='0',ed.cur=i;
            ed.s[i]=ch-'0';
        }
        st.step=ed.step=0;
        st.n=cantor(st.s);ed.n=(cantor(ed.s));
        printf("Case %d: ",kase);
        if(st.n==ed.n){cout<<0<<endl<<endl;continue;}
        bfs();
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值