1. 程式人生 > >1043(逆向搜尋bfs+康拓展開)

1043(逆向搜尋bfs+康拓展開)

傳送門

題意:給出一個初始的八數碼的狀態,然後問經過那些步驟可以轉化到八數碼的排列狀態

題解:首先需要了解一下康拓展開是個啥,那麼進入傳送門(大神的程式碼可以先不看),然後瞭解了這個黑科技後呢,就得考慮如何實現的問題了,多組資料,如果對於每一個狀態我們都"正向"進行一次bfs,那麼豈不是時間要爆炸,仔細思考一番,不如逆向搜尋出每種狀態,每個狀態算出康拓展開值,並標記方向(逆著),通過康拓展開值進行標記父子關係,最後對於每組資料,只需要算出此時的康拓展開值,如果有,輸出答案,沒有輸出無解即可。

附上長長的程式碼:


#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>

using namespace std;

const int maxn=3700000;//考慮下八數碼的最大康拓展開值

struct node1{
    char way;
    int fath;
};
node1 Node[maxn];

struct node2{
    int aa[10],n,val;
};

int dir[][2]={{0,1},{-1,0},{0,-1},{1,0}};
int fac[10];
//康拓展開板子
void set_fac()
{
    fac[0]=1;
    for(int i=1;i<=8;i++){
        fac[i]=fac[i-1]*i;
    }
}
int cantor(int aa[])
{
    int ans=0,k;
    for(int i=0;i<9;i++){
        k=0;
        for(int j=i+1;j<9;j++){
            if(aa[i]>aa[j]){
                k++;
            }
        }
        ans+=k*fac[8-i];
    }
    return ans;
}

void bfs(int a[])
{
    queue<node2>Q;
    node2 temp1;
    for(int i=0;i<9;i++){
        temp1.aa[i]=a[i];
    }
    temp1.n=8;
    temp1.val=0;//可以設最終狀態的康拓展開值為0
    Node[temp1.val].fath=0;
    Q.push(temp1);
    while(!Q.empty()){
        temp1=Q.front();
        Q.pop();
        for(int i=0;i<4;i++){
            node2 temp2=temp1;
            int tx=temp1.n/3+dir[i][0];
            int ty=temp1.n%3+dir[i][1];
            if(tx>=0&&ty>=0&&tx<3&&ty<3){
                temp2.n=tx*3+ty;
                swap(temp2.aa[temp2.n],temp2.aa[temp1.n]);
                temp2.val=cantor(temp2.aa);
                if(Node[temp2.val].fath==-1){
                    Node[temp2.val].fath=temp1.val;
                    if(i==0){Node[temp2.val].way='l';}
                    if(i==1){Node[temp2.val].way='d';}
                    if(i==2){Node[temp2.val].way='r';}
                    if(i==3){Node[temp2.val].way='u';}
                    Q.push(temp2);
                }
            }
        }
    }
}

int main()
{
    set_fac();
    int a[10];
    for(int i=0;i<9;i++){
        a[i]=i+1;
    }
    for(int i=0;i<370000;i++){
        Node[i].fath=-1;
    }
    bfs(a);
    char ch[50];
    int ss[10];
    while(gets(ch)>0){
        for(int i=0,j=0;ch[i]!=0;i++){
            if(ch[i]=='x'){
                ss[j++]=9;
            }else if(ch[i]>='0'&&ch[i]<='8'){
                ss[j++]=ch[i]-'0';
            }
        }
        int s=cantor(ss);
        if(Node[s].fath==-1){
            printf("unsolvable\n");
            continue;
        }
        while(s!=0){
            printf("%c",Node[s].way);
            s=Node[s].fath;
        }
        printf("\n");
    }
    return 0;
}
/*
//確保下方向是否寫的無誤
1 2 3 4 5 x 7 8 6
1 2 3 4 5 6 7 x 8
*/