八数码问题:双向bfs,康拓展开,启发式搜索

//返回步数
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int Hash[15];
struct node {
    int f,h,g;
    int x,y;
    char map[3][3];
    friend bool operator<(const node &a,const node &b) {
        if(a.f==b.f) return a.g<b.g;
        return a.f>b.f;
    }
};
node start;
bool vis[500000];
int to[4][2]= {0,-1,0,1,-1,0,1,0};
int pos[][2]= {{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
int check() {//判断是否有解
    int i,j,k;
    int s[20];
    int cnt=0;
    for(i=0; i<3; i++) {
        for(j=0; j<3; j++) {
            s[3*i+j]=start.map[i][j];
            if(s[3*i+j]=='x') continue;
            for(k=3*i+j-1; k>=0; k--) {
                if(s[k]=='x') continue;
                if(s[k]>s[3*i+j]) cnt++;
            }
        }
    }
    if(cnt%2) return 0;
    return 1;
}
int solve(node a) { //康托展开
    int i,j,k;
    int s[20];
    int ans=0;
    for(i=0; i<3; i++) {
        for(j=0; j<3; j++) {
            s[3*i+j]=a.map[i][j];
            int cnt=0;
            for(k=3*i+j-1; k>=0; k--) {
                if(s[k]>s[3*i+j]) cnt++;
            }
            ans=ans+Hash[i*3+j]*cnt;
        }
    }
    return ans;
}
int get_h(node a) {//计算h值,即曼哈顿距离
    int i,j;
    int ans=0;
    for(i=0; i<3; i++) {
        for(j = 0; j<3; j++) {
            if(a.map[i][j]=='x') continue;
            int k=a.map[i][j]-'1';
            ans+=abs(pos[k][0]-i)+abs(pos[k][1]-j);
        }
    }
    return ans;
}
int bfs() {//启发式搜索
    memset(vis,0,sizeof(vis));
    priority_queue<node> Q;
    start.g=0;
    start.h=get_h(start);
    start.f=start.h;
    vis[solve(start)]=true;
    if(solve(start)==0)  return 0;
    Q.push(start);
    node next;
    while(!Q.empty()) {
        node a=Q.top();
        Q.pop();
        int k_s=solve(a);
        vis[k_s]=true;
        for(int i=0; i<4; i++) {
            next=a;
            next.x+=to[i][0];
            next.y+=to[i][1];
            if(next.x<0||next.y<0||next.x>2||next.y>2) continue;
            next.map[a.x][a.y]=a.map[next.x][next.y];
            next.map[next.x][next.y]='x';
            next.g+=1;
            next.h=get_h(next);
            next.f=next.g+next.h;
            int k_n=solve(next);
            if(k_n==0) return next.g;
            if(vis[k_n]) continue;
            Q.push(next);
        }
    }
}
int main() {
    Hash[0]=1;
    for(int i=1; i<=9; i++) Hash[i]=Hash[i-1]*i;
    int t;
    cin>>t;
    for(int i=0; i<t; i++) {
        for(int i=0; i<3; i++) {
            for(int j=0; j<3; j++) {
                char a;
                cin>>a;
                start.map[i][j]=a;
                if(a=='0') {
                    start.map[i][j]='x';
                    start.x=i;
                    start.y=j;
                }
            }
        }
        if(!check()) {
            cout<<"No Solution!"<<endl;
        } else cout<<bfs()<<endl;
    }
}
//返回怎么走
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 3;
struct sta{
    int x,y;
};
char mp[maxn][maxn];
sta s[11];
int nowx,nowy;
int h(){
    int tmp = 0;
    for(int i = 0; i < 9; i++){
        int x = i/3,y = i%3;
        if(mp[x][y] == 'X') continue;
        tmp += abs(x - s[mp[x][y]-'0'].x) + abs(y - s[mp[x][y]-'0'].y);
    }
    return tmp;
}
int ans[200],limit;//怎么走,步数
const int dir[4][2] = {1,0,0,-1,0,1,-1,0};
const char d[4] = {'d','l','r','u'};
bool ok;
int IDAstar(int x,int y,int p,int cur){//递归搜索
    int bound = INF,tmp;
    int hv = h();
    if(cur + hv > limit) return cur + hv;
    if(hv == 0) {ok = true;return cur;}
    for(int i = 0; i < 4; i++){
        if(i == p) continue;
        int tx = x + dir[i][0];
        int ty = y + dir[i][1];
        if(tx < 0 || tx >= 3 || ty < 0 || ty >= 3) continue;
        swap(mp[x][y],mp[tx][ty]);
        ans[cur] = i;
        int nbound = IDAstar(tx,ty,3-i,cur+1);
        if(ok) return nbound;
        bound = min(bound,nbound);
        swap(mp[x][y],mp[tx][ty]);
    }
    return bound;
}
int main() {
    int t,cs = 1;
    char ch;
    scanf("%d",&t);
    getchar();
    while(t--){
        for(int i = 0; i < 9; i++){
            ch = getchar();
            if(ch == 'X'){
                nowx = i/3;
                nowy = i%3;
            }
            mp[i/3][i%3] = ch;
        }
        getchar();
        for(int i = 0; i < 9; i++){
            ch = getchar();
            if(ch == 'X') continue;
            s[ch-'0'] = {i/3,i%3};
        }
        getchar();
        limit = h();
        ok = false;
        while(!ok) limit = IDAstar(nowx,nowy,-10,0);
        printf("Case %d: %d\n",cs++,limit);
        for(int i = 0; i < limit; i++)
            putchar(d[ans[i]]);
        putchar('\n');
    }
    return 0;
}

//双向BFS,返回怎么走
#include<stdio.h>
#include<vector>
#include<queue>
#include<set>
#include<string.h>
#include<map>
using namespace std;
char s[15];
set<int>ss2;
int a[15];
int  f[15]= {1,1,2,6,24,120,720,5040,40320,362880};
const int maxn=1e6+5;
inline int judge() {
    int tot1=0;
    for(int i=0; i<=8; i++)
        for(int j=0; j<i; j++) {
            if(s[i]!='x'&&s[j]!='x')
                if(s[i]<s[j]) tot1++;
        }
    if(tot1%2==0) return 1;
    else return 0;
}
inline int kt(int n) { //n表示该排列有n个数 计算a[]是 1~n 的 第几个排列
    int sum = 0;
    for(int i = 0; i < n; i++) {
        int temp = 0;
        for(int j = i + 1; j < n; j++)
            if(a[j] < a[i])
                temp ++;
        sum += f[n - 1 - i] * temp;//f[n]表示n的阶乘
    }
    return sum + 1;
}
void _cantor(int n,int x) { //构造1~n的第x个排列
    x--;
    bool tmp[n+1];//= {0};
    memset(tmp,0,sizeof tmp);
    for(int i=n-1; i>=0; i--) {
        int k=x/f[i];
        x%=f[i];
        int j=1;
        for(int sum=0; sum<k||tmp[j]; j++)
            if(!tmp[j])sum++;
        a[n-1-i]=j;
        tmp[j]=1;
    }
}
vector<char>v;
char c[4]= {'u','d','l','r'};
char c2[4]= {'d','u','r','l'};
struct node {
    int id,pre,op,pos_9;//0--up 1--down 2--left 3--right
    node() {}
    node(int id,int pre,int op,int pos_9):id(id),pre(pre),op(op),pos_9(pos_9) {}
} q[maxn],q2[maxn];
int cc2,rr2;
map<int,int>ss;
void print(int rr2) {
    v.clear();
    int tp=ss[q2[rr2].id];
    while(q[tp].pre!=-1) {
        v.push_back(c[q[tp].op]);
        tp=q[tp].pre;
    }
    for(int i=v.size()-1; i>=0; i--) {
        printf("%c",v[i]);
    }
    v.clear();
    tp=rr2;
    while(q2[tp].pre!=-1) {
        v.push_back(c2[q2[tp].op]);
        tp=q2[tp].pre;
    }
    for(int i=0; i<v.size(); i++) {
        printf("%c",v[i]);
    }
    printf("\n");
}
int ff;
void bfs2() {
    node now=q2[cc2++];
    _cantor(9,now.id);
    int pos_9=now.pos_9;
    int t;
    int flag=0;
    for(int i=0; i<4; i++) {
        pos_9=now.pos_9;
        flag=0;
        if(i==0) {
            if(pos_9<=2)continue;
            flag=1;
            swap(a[pos_9],a[pos_9-3]);
        } else if(i==1) {
            if(pos_9>=6)continue;
            flag=1;
            swap(a[pos_9],a[pos_9+3]);
        } else if(i==2) {
            if(pos_9%3==0)continue;
            flag=1;
            swap(a[pos_9],a[pos_9-1]);
        } else {
            if((pos_9+1)%3==0)continue;
            flag=1;
            swap(a[pos_9],a[pos_9+1]);
        }
        int tp=kt(9);
        if(ss.count(tp)) {
            q2[rr2++]=node(tp,cc2-1,i,8);
            print(rr2-1);
            ff=1;
            return ;
        }
        if(!ss2.count(tp)) {
            int new_pos;
            for(int j=0; j<9; j++) {
                if(a[j]==9) {
                    new_pos=j;
                    break;
                }
            }
            q2[rr2++]=node(tp,cc2-1,i,new_pos);
            ss2.insert(tp);
        }
        if(flag) {
            if(i==0) {
                swap(a[pos_9],a[pos_9-3]);
            } else if(i==1) {
                swap(a[pos_9],a[pos_9+3]);
            } else if(i==2) {
                swap(a[pos_9],a[pos_9-1]);
            } else {
                swap(a[pos_9],a[pos_9+1]);
            }
        }
    }
}
void bfs(int be,int p9) {
    int rr=0,cc=0;//cc队头 rr队尾
    q[rr++]=(node(be,-1,-1,p9));
    node now,nxt;
    ss[be]=0;
    while(cc<rr) {
        now=q[cc++];
        _cantor(9,now.id);
        int pos_9=now.pos_9;
        int t;
        int flag=0;
        for(int i=0; i<4; i++) {
            pos_9=now.pos_9;
            flag=0;
            if(i==0) {
                if(pos_9<=2)continue;
                flag=1;
                swap(a[pos_9],a[pos_9-3]);
            } else if(i==1) {
                if(pos_9>=6)continue;
                flag=1;
                swap(a[pos_9],a[pos_9+3]);
            } else if(i==2) {
                if(pos_9%3==0)continue;
                flag=1;
                swap(a[pos_9],a[pos_9-1]);
            } else {
                if((pos_9+1)%3==0)continue;
                flag=1;
                swap(a[pos_9],a[pos_9+1]);
            }
            int tp=kt(9);
            if(!ss.count(tp)) {
                int new_pos;
                for(int j=0; j<9; j++) {
                    if(a[j]==9) {
                        new_pos=j;
                        break;
                    }
                }
                ss[tp]=rr;
                q[rr++]=node(tp,cc-1,i,new_pos);
            }
            if(flag) {
                if(i==0) {
                    swap(a[pos_9],a[pos_9-3]);
                } else if(i==1) {
                    swap(a[pos_9],a[pos_9+3]);
                } else if(i==2) {
                    swap(a[pos_9],a[pos_9-1]);
                } else {
                    swap(a[pos_9],a[pos_9+1]);
                }
            }
        }
        bfs2();
        if(ff)return ;
    }
}
int main() {
    while(~scanf("%c %c %c %c %c %c %c %c %c",&s[0],&s[1],&s[2],&s[3],&s[4],&s[5],&s[6],&s[7],&s[8])) {
        ss.clear();
        ss2.clear();
        if(strcmp(s, "12345678x") == 0) {
            puts("");
        } else if(!judge())
            printf("unsolvable\n");
        else {
            int p9;
            for(int i=8; i>=0; i--) {
                if(s[i]=='x') {
                    p9=i;
                    a[i]=9;
                } else
                    a[i]=s[i]-'0';
            }
            cc2=rr2=0;
            q2[rr2++]=node(1,-1,-1,8);
            ff=0;
            int be=kt(9);
            bfs(be,p9);
        }
        getchar();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42756710/article/details/81286236