16哈理工新生赛 E Nine Digits (BFS+康拓展开)

题目链接:点击打开链接

Nine Digits
Time Limit: 3000 MSMemory Limit: 32768 K
Total Submit: 69(19 users)Total Accepted: 16(12 users)Rating: Special Judge: No
Description
Input

多组数据,每组测试数据输入9个整数,为1-9的一个全排列。初始状态会被描述为

1 2 3 4 5 6 7 8 9

Output

输出所需要的最小移动步数。

Sample Input

1 2 3 4 5 6 7 8 9

9 8 7 6 5 4 3 2 1


Sample Output

0

12


Source
2016级新生程序设计全国邀请赛

题解:

一看题目,我就想到BFS,就是把所有情况搜出来,也就是9的阶乘362880种情况。但是由于不能够建立一个九位数的数组来保存这些数据,因此这里需要用到康托展开。

康托展开的使用范围是对于n个数的排列进行状态的压缩和存储,例如要对9的全排列进行判重.没有必要开一个10的9次幂的数组,因此它有362880中情况。因此其思想就是相当于一个哈希函数。一个排列它所对应的位置就是它排的是第几大。比如321,对应的值就是6,因为前面有123,132,213,231,312比它小。下面的cantor( )函数就是。

做完康托展开后,就要实现四种情况的变换,这个也比较简单,使用四个函数来实现即可,但是写的过程需要特别小心。

AC代码:

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int MAX=362880;
int s[9]={1,10,100,1000,10000,100000,1000000,10000000,100000000};
int jie[10]={0,1,2,6,24,120,720,5040,40320,362880};
int visit[MAX];
int len[MAX];
int four[4];

int lu(int num)
{
    int result;
    result=num%s[4];
    result+=((num/s[5])%10)*s[4];
    result+=num/s[8]*s[5];
    result+=((num/s[6])%10)*s[6];
    result+=((num/s[4])%10)*s[7];
    result+=((num/s[7])%10)*s[8];
    return result;
}

int ru( int num )  
{  
    int result = num/s[5]*s[5];  
    result += num/s[1]%10;  
    result += num/s[4]%10*s[1];  
    result += num/s[2]%10*s[2];  
    result += num%10*s[3];  
    result += num/s[3]%10*s[4];  
  
    return result;  
}  
  
int ld( int num )  
{  
    int result = num/s[6]*s[6] + num%10;  
  
    result += num/s[2]%10*s[1];  
    result += num/s[5]%10*s[2];  
    result += num/s[3]%10*s[3];  
    result += num/s[1]%10*s[4];  
    result += num/s[4]%10*s[5];  
  
    return result;  
}  
  
int rd( int num )  
{  
    int result = num % s[3] + num/s[8]*s[8];  
  
    result += num/s[4]%10*s[3];  
    result += num/s[7]%10*s[4];  
    result += num/s[5]%10*s[5];  
    result += num/s[3]%10*s[6];  
    result += num/s[6]%10*s[7];  
  
    return result;  
}  
int cantor(int key) //康拓展开 
{
    int result,temp[9];
    for(int i=8;i>=0;i--)
    {
        temp[i]=key%10;
        key=key/10;
    }
    result=0;

    for(int i=0;i<8;i++)
    {
        int tot=0;
        for(int j=i+1;j<9;j++)
            if(temp[j]<temp[i])
                tot++;
        result+=tot*jie[8-i];
    }
    return result;
}
int key2[4];
int start=123456789;
queue<int>que;
int main()
{

    
    int temp;
    int key1;
    len[0]=0;
    que.push(start);
    visit[0]=1;
    while(!que.empty())
    {
        temp=que.front();
        que.pop();
        key1=cantor(temp);
        four[0]=lu(temp);

        four[1]=ru(temp);

        four[2]=ld(temp);

        four[3]=rd(temp);

        for(int i=0;i<4;i++)
        {
            key2[i]=cantor(four[i]);
            if(!visit[key2[i]])
            {
                visit[key2[i]]=1;
                que.push(four[i]);
                
                len[key2[i]]=len[key1]+1;
            }
        }
    }
    
    int input[9];
    while(~scanf("%d",&input[0]))
    {
        temp=input[0];
        for(int i=1;i<9;i++)
        {
            scanf("%d",&input[i]);
            temp=input[i]+temp*10;
        }
        printf("%d\n",len[cantor(temp)]);
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值