hdu 1043(八数码问题)

<span style="font-family: Arial, Helvetica, sans-serif;">题意:省略</span>

 解题思路:针对八数码问题,如果x往左或往右走,是不会改变逆序数大小的,且往上或往下走只有三种情况,讨论往下走,如果与x交换的数是ai,则要判断的是a(i-1),a(i-2)与ai的关系.

                 只会出现四种情况,a(i-1)>ai,a(i-2)>ai;逆序对数在原来的基础上+2

 a(i-1)<ai,a(i-2)>ai;逆序对数在原来的基础上不变

                                                 a(i-1)>ai,a(i-2)<ai;逆序对数在原来的基础上不变

 a(i-1)<ai,a(i-2)<ai;逆序对数在原来的基础上-2

 针对上述四种情况,逆序数的初始值为0,则经过各种变换逆序数为偶数,则若一种状态逆序数为奇数,始不可能的。且在保存状态时利用康托展开:X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! (ai为某个数对应的逆序对数,达到状态压缩)。

 这里要利用反向的思维,通过最终状态去bfs所有状态。          





                 只会出现四种情况,a(i-1)>ai,a(i-2)>ai;逆序对数在原来的基础上+2

 a(i-1)<ai,a(i-2)>ai;逆序对数在原来的基础上不变

                                                 a(i-1)>ai,a(i-2)<ai;逆序对数在原来的基础上不变

 a(i-1)<ai,a(i-2)<ai;逆序对数在原来的基础上-2

 针对上述四种情况,逆序数的初始值为0,则经过各种变换逆序数为偶数,则若一种状态逆序数为奇数,始不可能的。且在保存状态时利用康托展开:X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! (ai为某个数对应的逆序对数,达到状态压缩)。

 这里要利用反向的思维,通过最终状态去bfs所有状态。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <queue>
using namespace std;
#define MAXN 50
#define MAZE 600000
typedef struct node{
    char str[50];
    int nx[9];
    int num,hashnum,xind;
    node();
    node(char *ss,int nu,int hanu,int *nnx){
        strcpy(str,ss);
        num = nu;
        hashnum = hanu;
        for(int i=0;i<9;++i){
            nx[i] = nnx[i];
        }
    }
    void charstr(){
        int tmp = 0;
        int tmpc;
        int tmpnum = num;
        tmpc = 9;
        int zflag = 0;
        while(num){
            zflag = num%10;
            str[tmpc -1] = '0'+ zflag;
            if(zflag==9)
                tmp = tmpc - 1;
            num/=10;
            --tmpc;
        }
        num = tmpnum;
        xind = tmp;
        //return tmp;
    }
};
queue<node>q;
int path[MAZE];
int nx[9];
int pa[MAZE],ans[MAZE];
bool vis[MAZE];
char nows[MAXN];
int cnt;
int p[]={1,1,2,6,24,120,720,5040,40320};
int pw[] = {100000000,10000000,1000000,100000,10000,1000,100,10,1};
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
int goal;
void prepro(){
    cnt = 0;
    int len = (int)strlen(nows);
    for(int i=0;i<len;++i){
        if(nows[i]==32)continue;
        if(nows[i]=='x')nows[i] = '9';
        nows[cnt++] = nows[i];
    }
    nows[cnt] = 0;
}
void init(){
    memset(vis,false,sizeof(vis));
    memset(pa,-1,sizeof(pa));
}
int charhash(char *str){
    //就保证系数ai》=0&&ai<=(8 - i)
    int ans = 0,tmpc;
    int st = 0;
    for(int i=0;i<cnt;++i){
        //if(nows[i]=='x')continue;
        tmpc = 0;
        for(int j = i+1;j<cnt;++j){
            //  if(nows[j]=='x')continue;
            if(str[i]>str[j])tmpc++;
        }
        nx[i] = tmpc;
        ans+=tmpc*p[8-i];
        //st++;
    }
    return ans;
}

int getnx(){
    int ans = 0;
    for(int i=0;i<cnt;++i){
        //if(nows[i]=='x')continue;
        if(nows[i]=='9')continue;
        for(int j=i+1;j<cnt;++j){
            // if(nows[j]=='x')continue;
            if(nows[i]>nows[j])
                ans++;
        }
    }
    return ans;
}
int getnumber(){
    int   ans = 123456789;
    return ans;
}
//右 左 下 上
int gethash(char *str,int num,int dir,int xind,int nxind,node &no){
    int tmpcc;
    if(dir==0){
        
        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind];
        tmpcc = no.nx[nxind];
        no.nx[nxind]=no.nx[xind] - 1;
        no.nx[xind] = tmpcc;
        num+=p[8-xind]*no.nx[xind]  + p[8-nxind]*no.nx[nxind];
    }
    if(dir==1){
        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind];
        tmpcc = no.nx[nxind];
        no.nx[nxind]=no.nx[xind] + 1;
        no.nx[xind] = tmpcc;
        num+=p[8-xind]*no.nx[xind]  + p[8-nxind]*no.nx[nxind];
    }
    
    if(dir==2){
        int ind1,ind2;
        ind1 = xind+1;
        ind2 = xind+2;
        int cc = 0;
        if(str[nxind]>str[ind1])cc++;
        if(str[nxind]>str[ind2])cc++;
        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind];
        tmpcc = no.nx[nxind];
        no.nx[nxind]=no.nx[xind] - 3;
        no.nx[xind] = tmpcc+cc;
        num+=p[8-xind]*no.nx[xind]  + p[8-nxind]*no.nx[nxind];
        if(str[nxind]<str[ind1]){
            num-=p[8-ind1];
            no.nx[ind1]--;
        }
        if(str[nxind]<str[ind2]){
            num-=p[8-ind2];
            no.nx[ind2]--;
        }
    }
    if(dir==3){
        int ind1,ind2;
        ind1 = xind-1;
        ind2 = xind-2;
        int cc = 0;
        if(str[nxind]>str[ind1])cc++;
        if(str[nxind]>str[ind2])cc++;
        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind];
        tmpcc = no.nx[nxind];
        no.nx[nxind]=no.nx[xind] + 3;
        no.nx[xind] = tmpcc-cc;
        num+=p[8-xind]*no.nx[xind]  + p[8-nxind]*no.nx[nxind];
        if(str[nxind]<str[ind1]){
            num+=p[8-ind1];
            no.nx[ind1]++;
        }
        if(str[nxind]<str[ind2]){
            num+=p[8-ind2];
            no.nx[ind2]++;
        }
        
    }
    return num;
}
//右 左 下 上
void restart(char *str,int num,int dir,int xind,int nxind,node &no){
    int tmpcc;
    if(dir==0){
        //        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind] + p[8-xind]*(no.nx[nxind]-1)  + p[8-nxind]*no.nx[xind];
        tmpcc = no.nx[xind];
        no.nx[xind]=no.nx[nxind] + 1;
        no.nx[nxind] = tmpcc;
    }
    if(dir==1){
        //        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind] + p[8-xind]*(no.nx[nxind]+1)  + p[8-nxind]*no.nx[xind];
        tmpcc = no.nx[xind];
        no.nx[xind]=no.nx[nxind] - 1;
        no.nx[nxind] = tmpcc;
        
    }
    
    if(dir==2){
        int ind1,ind2;
        ind1 = xind+1;
        ind2 = xind+2;
        int cc = 0;
        if(str[nxind]>str[ind1])cc++;
        if(str[nxind]>str[ind2])cc++;
        //        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind] + p[8-xind]*(no.nx[nxind]-2)  + p[8-nxind]*(no.nx[xind]+cc);
        tmpcc = no.nx[xind];
        no.nx[xind]=no.nx[nxind] + 3;
        no.nx[nxind] = tmpcc-cc;
        if(str[nxind]<str[ind1]){
            // num+=p[8-ind1];
            no.nx[ind1]++;
        }
        if(str[nxind]<str[ind2]){
            //num+=p[8-ind2];
            no.nx[ind2]++;
        }
    }
    if(dir==3){
        //        num = num-p[8-xind]*no.nx[xind]  - p[8-nxind]*no.nx[nxind] + p[8-xind]*(no.nx[nxind]+2)  + p[8-nxind]*(no.nx[xind]-cc);
        int ind1,ind2;
        ind1 = xind-1;
        ind2 = xind-2;
        int cc = 0;
        if(str[nxind]>str[ind1])cc++;
        if(str[nxind]>str[ind2])cc++;
        tmpcc = no.nx[xind];
        no.nx[xind]=no.nx[nxind] - 3;
        no.nx[nxind] = tmpcc+cc;
        if(str[nxind]<str[ind1]){
            //num-=p[8-ind1];
            no.nx[ind1]--;
        }
        if(str[nxind]<str[ind2]){
            //num=p[8-ind2];
            no.nx[ind2]--;
        }
    }
    //    return num;
}
void solve(){
    //int front,rear;
    //    if(getnx()&1)
    //        return false;
    int num = getnumber();
    int hashnum;
    hashnum = charhash("123456789");
    node no("123456789",num,hashnum,nx);
    no.charstr();
    q.push(no);
    //vis[num] = true;
    int tmpnum,xind,nxind;
    int x,y,nx,ny;
    while(!q.empty()){
        no = q.front();
        q.pop();
        //  num = no.num;
        //if(goal==no.hashnum)return true;
        xind = no.xind;
        if(vis[no.hashnum])continue;
        vis[no.hashnum] = true;
        //xind = charstr(num);
        x = xind/3;
        y = xind%3;
        for(int i=0;i<4;++i){//右 左 下 上
            nx = x + dx[i];
            ny = y + dy[i];
            if(nx>=0&&nx<3&&ny>=0&&ny<3){
                nxind = nx*3+ny;
                tmpnum = gethash(no.str,no.hashnum,i,xind,nxind,no);
                int cc = no.str[nxind] - '0';
                no.str[xind] = no.str[nxind];
                no.str[nxind] = '9';
                // int chc = charhash(no.str);
                int t1,t2;
                //  t1 = no.num;
                t2 = no.hashnum;
                if(!vis[tmpnum]){
                    pa[tmpnum] = no.hashnum;
                    path[tmpnum] = i;
                    //   int tmpcc = num +  (9 - cc)*(pw[nxind]-pw[xind]);
                    //  no.num = tmpcc;
                    no.hashnum = tmpnum;
                    no.xind = nxind;
                    q.push(no);
                }
                no.str[nxind] = no.str[xind];
                no.str[xind] = '9';
                // no.num = t1;
                no.hashnum = t2;
                no.xind = xind;
                restart(no.str,no.hashnum,i,xind,nxind,no);
            }
        }
    }
    //   return false;
}
int getdir(int num){
    switch(num){
        case 0: return 'l';
        case 1: return 'r';
        case 2: return 'u';
        case 3: return 'd';
    }
    return  0;
}
void output(bool flag,int hashnum){
    if(!flag){
        printf("unsolvable\n");
        return;
    }
    int cntans = 0;
    int tmp = hashnum;
    //char ss[]="ullddrurdllurdruldr";
    //printf("%d\n",strlen(ss));
    while(1){
        if(pa[tmp]==-1)break;
        ans[cntans++] = path[tmp];
        tmp = pa[tmp];
        
    }
    //printf("%d",ans[0]);
    // printf("%d\n",cntans);
    for(int i=0;i<cntans;++i){
        putchar(getdir(ans[i]));
    }
    printf("\n");
}
void clear(){
    while(!q.empty()){
        q.pop();
    }
}
int main(){
    init();
    goal = 0;
    solve();
    //clear();
    bool flag;
    while(gets(nows)){
        flag = true;
        prepro();
        int hashnum = charhash(nows);
        if(!vis[hashnum])flag = false;
        output(flag,hashnum);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值