[ZJOI2005]九数码游戏

[ZJOI2005]九数码游戏

题目描述

输入输出格式

输入格式:

 

输入文件中包含三行三列九个数,同行的相邻两数用空格隔开,表示初始状态每个方格上的数字。初始状态不会是目标状态。

 

输出格式:

 

如果目标状态无法达到,则输出“UNSOLVABLE”(引号不输出)。

否则,第一行是一个整数S,表示最少的操作次数。接下来4 × (S + 1)行,每四行表示一个状态:前三行每行三个整数,相邻两数用空格隔开,表示每个方格上的数字,第四行是一个空行,作为分隔。第一个状态必须是初始状态,最后一个状态必须是目标状态。

 

输入输出样例

输入样例#1:
2 3 0
1 8 7
5 4 6
输出样例#1:
4
2 3 0
1 8 7
5 4 6

1 2 3
5 8 0
4 6 7

1 2 3
0 5 8
4 6 7

0 1 2
4 5 3
6 7 8

0 1 2
3 4 5
6 7 8

因为这是3*3的全排列矩阵变换;
最多有9!(362880)种状态;
用BFS,搜到终点为止,中间记录一下路径;
将3*3的全排列映射成一一对应的数,可以用康托展开;
最好不要用map,可能会超时;

#include<iostream>  
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<map>  
using namespace std;  

int a[9],q[400008],st,ed,b[9],f[9],ge,ans;
int c[400008],hash[400008];
int  fac[10]={1,1,2,6,24,120,720,5040,40320}; 

int calc1()  
{  
    int i,j,t,sum;  
    sum=0;  
    for(i=0;i<9;i++)  
    {  
        t=0;  
        for(j=i+1;j<9;j++)  
            if(a[i]>a[j])  
                ++t;  
        sum+=t*fac[9-i-1];  
    }  
    return sum+1;  
}  

int calc()  
{  
    int i,j,t,sum;  
    sum=0;  
    for(i=0;i<9;i++)  
    {  
        t=0;  
        for(j=i+1;j<9;j++)  
            if(b[i]>b[j])  
                ++t;  
        sum+=t*fac[9-i-1];  
    }  
    return sum+1;  
}  

void fen(int x)  
{   
    int i,j,t,vst[9]={0};
    x--; 
    for(i=0;i<9;i++)  
    {  
        t=x/fac[9-i-1];  
        for(j=0;j<9;j++)  
            if(!vst[j])  
            {
                if(t==0) break;  
                --t;  
            }
        b[i]=j;
        vst[j]=1;
        x%=fac[9-i-1];
    }  
}  

int main()  
{  
    int x=0;
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++){
            scanf("%d",&a[(i-1)*3+j-1]);
        }
    x=calc1();
    ge=1;
    if(x==ge){
        printf("0");
        return 0;
    }
    q[1]=x;
    hash[x]=-1;
    st=0; ed=1;
    while(st<ed){
        int x=q[++st];
        fen(x);
        for(int i=0;i<9;i++)
            f[i]=b[i];
        b[3]=f[5];
        b[4]=f[3];
        b[5]=f[4];
        int y=calc();
        if(hash[y]==0){
            hash[y]=x;
            ed++;
            q[ed]=y;
        }
        if(y==ge)
            break;
        b[3]=f[3];
        b[4]=f[4];
        b[5]=f[5];
        
        b[0]=f[3];
        b[1]=f[0];
        b[2]=f[1];
        b[5]=f[2];
        b[8]=f[5];
        b[7]=f[8];
        b[6]=f[7];
        b[3]=f[6];
        
        y=calc();
        if(hash[y]==0){
            hash[y]=x;
            ed++;
            q[ed]=y;
        }
        if(y==ge)
            break;
    }
    x=hash[ge];
    if(x==0){
        printf("UNSOLVABLE\n");
        return 0;
    }
    while(x!=-1){
        ans++;
        c[ans]=x;
        x=hash[x];
    }
    printf("%d\n",ans);
    for(int i=ans;i>0;i--){
        fen(c[i]);
        printf("%d %d %d\n",b[0],b[1],b[2]);
        printf("%d %d %d\n",b[3],b[4],b[5]);
        printf("%d %d %d\n",b[6],b[7],b[8]);
        printf("\n");
    }
    if(ans>=1){
        printf("0 1 2\n");
        printf("3 4 5\n");
        printf("6 7 8\n");
    }
}

 




转载于:https://www.cnblogs.com/WQHui/p/7677338.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值