CDOJ 485 UESTC 485 Game

题意:八数码,但是转移的方式是转动,一共十二种,有多组询问,初态唯一,终态不唯一。

题解:初态唯一,那么可以预处理出012345678的所有转移情况,然后将初态对012345678做一个映射,再枚举一下终态的所有情况,取最小值即可。

不得不学了逆cantor展开,cantor展开是一个变进制数,每位上是原序列对应位置上的逆序值。那么求逆时候,就先除最大的位权得到对应位置上的逆序值,根据逆序值可以知道他在原序列中第几大,然后标记它,迭代。状态转移有点烦。一开始还担心超时,就打了个表直接存到程序里,结果超过30000bit代码长度限制了,笑cry。

#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
//#define local

const int maxn = 362880;
int d[maxn];
int fac[9] = { 1,1,2,6,24,120,720,5040,40320};//,362880
int St[9],Ed[9];

int cantor(int *e) {
        int ret = 0;
        for(int i = 0; i < 9; i++) {
            int cnt = 0;
            for(int j = i+1; j < 9; j++)
                if(e[j] < e[i]) cnt++;
            ret += fac[8-i] * cnt;
        }
        return ret;
}

void invCantor(int *a,int code)
{
    bool vis[10] = {0};
    for(int i = 0; i < 9; i++){
        int t = code/fac[8-i];
        int j;
        for( j = 0; j < 9 ; j++){
            if(!vis[j]){
                if(t == 0) break;
                t--;
            }
        }
        a[i] = j; vis[j] = 1;
        code %= fac[8-i];
    }
}

int dir[12][9] = {
{2,0,1,3,4,5,6,7,8},{0,1,2,5,3,4,6,7,8},{0,1,2,3,4,5,8,6,7},
{1,2,0,3,4,5,6,7,8},{0,1,2,4,5,3,6,7,8},{0,1,2,3,4,5,7,8,6},
{6,1,2,0,4,5,3,7,8},{0,7,2,3,1,5,6,4,8},{0,1,8,3,4,2,6,7,5},
{3,1,2,6,4,5,0,7,8},{0,4,2,3,7,5,6,1,8},{0,1,5,3,4,8,6,7,2} };
queue<int> q;

void BfsPre()
{
    memset(d,-1,sizeof(d) );
    d[0] = 0;
    q.push(0);
    while(q.size()){
        int u = q.front();q.pop();
        int tmp[9];
        invCantor(tmp,u);
        for(int i = 0; i < 12; i++){
            int tmp2[9];
            for(int j = 0; j < 9; j++){
                tmp2[j] = tmp[dir[i][j]];
            }
            int v = cantor(tmp2);
            if(~d[v]) continue;
            d[v] = d[u]+1;
            q.push(v);
        }
    }
}

int query()
{
    int mp[9];
    for(int i = 0; i < 9; i++) { mp[St[i]] = i; }
    bool appear[9] = {0};
    for(int i = 0; i < 9; i++){
       if(~Ed[i]) appear[Ed[i] = mp[Ed[i]]] = 1;
    }
    int vec[9],sz = 0;
    for(int i = 0; i < 9; i++) {
        if(!appear[i]) vec[sz++] = i;
    }
    if(sz == 9)  return 0;
    if(sz == 0) return d[cantor(Ed)];

    sort(vec,vec+sz);
    const int INF =  0x7fffffff;
    int ans = INF;
    int tmp[9];
     do{
        int j = 0;
        for(int i = 0; i < 9; i++){
            if(~Ed[i]) { tmp[i] = Ed[i]; }
            else { tmp[i] = vec[j++]; }
        }
        int Hash = cantor(tmp);
        if(~d[Hash]) ans = min(ans,d[Hash]);
    }while(next_permutation(vec,vec+sz));
    return ans!=INF? ans : -1;
}

int main()
{
#ifdef local
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
#endif // local
    int T;
    BfsPre();

    scanf("%d",&T);
    for(int k = 1; k <= T; k++){
        printf("Case #%d: ",k);
        for(int i = 0; i < 9; i ++){
            scanf("%d",St+i);
            St[i]--;
        }
        getchar();
        char buf[15];
        for(int i = 0; i < 3; i++){
            gets(buf);
            for(int j = 0; j < 5; j+=2){
                if(‘1‘<=buf[j] && buf[j] <= ‘9‘){
                    Ed[i*3+j/2] = buf[j] - ‘1‘;
                }else Ed[i*3+j/2] = -1;
            }
        }
        int ans = query();
        if(~ans) printf("%d\n",ans);
        else printf("No Solution!\n");
    }

    return 0;
}
时间: 2024-12-04 23:05:44

CDOJ 485 UESTC 485 Game的相关文章

UESTC 485 Game(康托,BFS)

Today I want to introduce an interesting game to you. Like eight puzzle, it is a square board with 9 positions, but it filled by 9 numbered tiles. There is only one type of valid move, which is to rotate one row or column. That is, three tiles in a r

CDOJ 490 UESTC 490 Swap Game

题意:有两种颜色的小球形成环,求最小交互次数使球相连. 题解:先解决另一个简单的问题,如果是一个链,把红球标记为1,蓝球标记为0,要排成升序需要多少次交换呢?答案是逆序对总数,原因是一次交互最多消除一个逆序对,而且有策略可以保证每次消除一个逆序对.要解决这个问题,需要做一些变通.看蓝球,因为是环,为了使交换次数最小,前半段的蓝球应该往前靠,所以在后半段的蓝球应该往后靠.那么就把原序列划分成两半,前面一段记红球为1,蓝球为0,后面一段记蓝球为1,红球为0,然后分别计算逆序对数,就可以求出以0位置前

liux之我用过的zip解压命令

用途说明 zip文件是一种常用的压缩文件格式,WinZip.WinRar等压缩软件都支持zip文件格式,就连java的jar包也是zip格式 的,Firefox插件xpi文件也是zip格式的.Linux在zip文件上的支持也是很周到的,它提供了zip.unzip和zcat等命令来支持. 本文的主题是讲一下使用unzip命令来解压zip格式的压缩文件.当我们需要把Windows上的很多文件(比如一个目录中的所有文件)上传到 Linux时,可以先把这些文件打包到一个zip文件中,然后再上传,再在Li

Oracle汉字转拼音package

--函数GetHzFullPY(string)用于获取汉字字符串的拼音 --select GetHzFullPY('中华人民共和国') from dual; --返回:ZhongHuaRenMinGongHeGuo --函数GetHzPYCAP(string)用于获取拼音首字母 --select GetHzPYCAP('中华人民共和国') from dual; --返回ZHRMGHG create or replace package GetHZPY is -- Author : ADMINIS

Oracle将Timestamp显示在页面

通过oracle的to_char函数转换 想要的数据格式 在oracle中to_char函数应用 Postgres 格式化函数提供一套有效的工具用于把各种数据类型(日期/时间,int,float,numeric)转换成格式化的字符串以及反过来从格式化的字符串转换成原始的数据类型. 注意:所有格式化函数的第二个参数是用于转换的模板. 表 5-7. 格式化函数 函数 返回 描述 例子 to_char(timestamp, text) text 把 timestamp 转换成 string to_ch

Oracle sql 中的字符(串)替换与转换[转载]

1.REPLACE 语法:REPLACE(char, search_string,replacement_string) 用法:将char中的字符串search_string全部转换为字符串replacement_string.       举例:SQL> select REPLACE('fgsgswsgs', 'fk' ,'j') 返回值 from dual;            返回值            ---------            fgsgswsgs SQL> sele

[书目]系统分析与设计教程(原书第7版)

作者简介 作者:(美国)舍利(Gary B.Shelly) (美国)Thomas J.Cashman (美国)Harry J.Rosendlatt 译者:史晟辉 王艳清 李芳 等 目录 出版者的话译者序前言第1章 系统分析与设计绪论11.1 信息技术的影响21.1.1 IT的未来21.1.2 系统分析与设计的作用31.1.3 谁开发信息系统41.2 信息系统组成41.2.1 硬件51.2.2 软件51.2.3 数据61.2.4 过程61.2.5 人61.3 了解企业71.3.1 企业概图71.3

绿卡排队

赴美工作常识(Part 6 - 绿卡排队) 2016-05-19 08:28 by Cat Chen, 250 阅读, 0 评论, 收藏, 编辑 上一篇<赴美工作常识(Part 5 - 绿卡优先级)>解释完排队的优先级是怎么确定的,以及 PERM 和 I–140 表的意义,接下来就要解释一下队具体是怎么排的以及排到之后的 I–485 表申请.这里必须要有免责声名.因为我不是移民律师,所以我只是说我的理解,法律问题还是需要咨询律师的. I–485 I–485 表不像 PERM 需要准备那么多材料

Oracle DBA管理包脚本系列(二)

该系列脚本结合日常工作,方便DBA做数据管理.迁移.同步等功能,以下为该系列的脚本,按照功能划分不同的包.功能有如下: 1)数据库对象管理(添加.修改.删除.禁用/启用.编译.去重复.闪回.文件读写.会话管理.表空用.用户/权限管理): 2)数据库分析: 3)数据库备份: 4)数据库同步: 5)数据库数据导出: 6)获取数据库对象源码: 7)数据库对比智能升级: ...... 更多功能请自行体验. 本系列包依赖于Oracle DBA管理包脚本系列系列(一)的脚本. EXEC PKG_DBMANA