sicily 2011. Nine Digits(广搜,康托展开)

来源:互联网 发布:下载zoom软件 编辑:程序博客网 时间:2024/06/09 22:33

2011. Nine Digits

Constraints

Time Limit: 2 secs, Memory Limit: 256 MB

Description

 Nine tiles, each with a number from 1 to 9 on it, are packed into a 3 by 3 frame. Your task is to arrange the tiles so that they are ordered as:

1 2 3
4 5 6
7 8 9
 
       At each step, you can do the following operation to the tiles: Choose 2 by 2 tiles, rotate the tiles in clockwise order. For example:
       1 2 3             4 1 3                           1 2 3             1 2 3
       4 5 6      =>   5 2 6             or           4 5 6      =>   4 8 5
       7 8 9             7 8 9                           7 8 9             7 9 6
 

       Write a program to find the minimum number of steps.

Input

 Input contains multiple test cases.

       Each test case is a description of a configuration of the nine tiles. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and from left to right within a row, where the tiles are represented by numbers 1 to 9. For example:
       9 8 7
       6 5 4
       3 2 1
is described by this list:
       9 8 7 6 5 4 3 2 1

Output

 Output the minimum number of steps on a single line for each test case.

Sample Input

1 2 3 4 5 6 7 8 94 1 3 5 2 6 7 8 9

Sample Output

03

Problem Source

每周一赛:2010中山大学新手赛


这道题应该是考查广搜+康托压缩(康托展开),广搜用于找最短路,康托压缩是一个特殊的哈希函数,这个哈希函数好就好在它仅仅是一个大小为36W的int数组,能够省下不小内存。其实康托压缩就是把一个排列变成数字,这个数字是全排列中的第几个元素,比如132是123的第二个排列,就输出2。通过这个数字还能逆推回原来的序列。详情见百度百科:康托展开    有了这两个关键方法,设计算法的时候不要按部就班地从当前状态找到123456789这种顺序思路想,因为这样的时间复杂度和查询的次数是成线性关系增加的,会超时。应该从123456789这个状态出发,去找到其他所有状态,这个状态数为9!(9的全排列,包含了这个游戏所有的情况),而且搜索的时候数字变成了逆时针旋转(反过来)。这样只需要搜索一次。最后就是打表过程了。

#include <bits/stdc++.h>using namespace std;int fact[10] = {0,1,2,6,24,120,720,5040,40320,362880};//阶乘表int src[10];int dst[10] = {1,2,3,4,5,6,7,8,9};int vis[400000];int ans[400000];struct pack{    int num,k;    pack(){}    pack(int num,int k):num(num),k(k){}};int cantor(int num){    int tmp[10];    int code=0;    for(int i=0;i<9;i++){        tmp[8-i]=num%10;        num/=10;    }           for(int i = 0;i <= 8;++i)//*****康托展开公式:当前位数的逆序数*该位数的阶乘****(本题重点)      {          int cnt = 0;          for(int j = i + 1;j <= 8;j++)              if(tmp[i] > tmp[j])    ++cnt;          code += fact[8-i] * cnt;      }     return code;}void op_1(int a[],int &num){    int tmp[10];    tmp[0]=a[1];    tmp[1]=a[4];    tmp[2]=a[2];    tmp[3]=a[0];    tmp[4]=a[3];    tmp[5]=a[5];    tmp[6]=a[6];    tmp[7]=a[7];    tmp[8]=a[8];    int hash=0;    for(int i=8;i>=0;i--){        hash+=tmp[i]*pow(10,8-i);    }    num = hash;}void op_2(int a[],int &num){    int tmp[10];    tmp[0]=a[0];    tmp[1]=a[2];    tmp[2]=a[5];    tmp[3]=a[3];    tmp[4]=a[1];    tmp[5]=a[4];    tmp[6]=a[6];    tmp[7]=a[7];    tmp[8]=a[8];    int hash=0;    for(int i=8;i>=0;i--){        hash+=tmp[i]*pow(10,8-i);    }    num = hash;}void op_3(int a[],int &num){    int tmp[10];    tmp[0]=a[0];    tmp[1]=a[1];    tmp[2]=a[2];    tmp[3]=a[4];    tmp[4]=a[7];    tmp[5]=a[5];    tmp[6]=a[3];    tmp[7]=a[6];    tmp[8]=a[8];    int hash=0;    for(int i=8;i>=0;i--){        hash+=tmp[i]*pow(10,8-i);    }    num = hash;}void op_4(int a[],int &num){    int tmp[10];    tmp[0]=a[0];    tmp[1]=a[1];    tmp[2]=a[2];    tmp[3]=a[3];    tmp[4]=a[5];    tmp[5]=a[8];    tmp[6]=a[6];    tmp[7]=a[4];    tmp[8]=a[7];    int hash=0;    for(int i=8;i>=0;i--){        hash+=tmp[i]*pow(10,8-i);    }    num = hash;}void bfs(){    memset(vis,0,sizeof(vis));    queue<pack> box;    int hash=0;    for(int i=8;i>=0;i--){        hash+=dst[i]*pow(10,8-i);    }    box.push(pack(hash,0));    while(!box.empty()){        int tmp[10];        int sum=box.front().num;        int k=box.front().k;        //cout<<sum<<endl;        box.pop();        //判重         int hash=cantor(sum);        if(vis[hash])        continue;        vis[hash]=1;        ans[hash]=k;                int cur[10];        int sum_tmp;        for(int i=0;i<9;i++){            cur[8-i]=sum%10;            sum/=10;        }        op_1(cur,sum_tmp);        box.push(pack(sum_tmp,k+1));        op_2(cur,sum_tmp);        box.push(pack(sum_tmp,k+1));        op_3(cur,sum_tmp);        box.push(pack(sum_tmp,k+1));        op_4(cur,sum_tmp);        box.push(pack(sum_tmp,k+1));    }}int main(){    bfs();    while(~scanf("%d",&src[0])){        for(int i=1;i<9;i++)        scanf("%d",&src[i]);        int hash=0;        for(int i=8;i>=0;i--){            hash+=src[i]*pow(10,8-i);        }        printf("%d\n",ans[cantor(hash)]);    }}                                 




1 0
原创粉丝点击