zoukankan      html  css  js  c++  java
  • Poj2286 The Rotation Game

    题目描述

    如下图所示,有一个"#"形的棋盘,上面有1,2,3三种数字各8个。给定8种操作,分别为图中的A~H。这些操作会按照图中字母和箭头所指明的方向,把一条长为8的序列循环移动1个单位。例如下图最左边的"#"形棋盘执行操作A后,会变为下图中间的"#"形棋盘,再执行操作C后会变成下图最右边的"#"形棋盘。给定一个初始状态,请使用最少的操作次数,使"#"形棋盘最中间的8个格子里的数字相同。

    img

    输入格式

    输入包括不超过 30组测试数据。每个测试数据只包括一行,包含 24个整数,每相邻两个整数之间用 1个空格隔开,表示这个 “#” 形棋盘的初始状态。(这些整数的排列顺序是从上至下,同一行的从左至右。例如1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3 表示图 1 最左边的状态。)每两组测试数据之间没有换行符。输入文件以一行 0结束。

    输出格式

    对于每组测试数据,输出两行。第一行用字符A∼H 输出操作的方法,每两个操作字符之间没有空格分开,如果不需要任何步数,输出 No moves needed。第二行输出最终状态中最中间的 8个格子里的数字。如果有多组解,输出操作次数最少的一组解;如果仍有多组解,输出字典序最小的一组。任意相邻两组测试数据的输出之间不需输出换行符。


    这么复杂的题......搜索吧

    当前的状态可以表示为:当前的棋盘、操作序列和操作次数。前两个可以开全局变量来存。

    考虑剪枝:

    1.上下界剪枝:

    上界:不好找

    下界:最好的情况就是当前棋盘的中间8个格子和目标状态的中间8个格子有多少不相同,即

    [sum_{i=0}^{7}[g[ctr[i]]≠des[ctr[i]]] ]

    其中ctr为center,表示中间格子。然而这个下界对剪枝没什么用

    2.搜索顺序优化:不好优化

    3.排除等效冗余:正着交换一遍再反着交换一遍是没有意义的,所以我们应该避免做与上一次相反的操作。

    4.最优化剪枝:设当前的答案为ans,那么当搜索深度>ans时就没必要搜了。

    5.记忆化:日常没有什么好记

    并没有剪掉多少对不对。然而这题的答案并不大,我们可以考虑用迭代加深来优化DFS。

    从1开始枚举搜索深度,由于IDFS第一次搜到的答案必定为最优解,所以当搜到答案之后就可以退出。那么最优化剪枝就没必要写了。

    然而我们加了一个优化的同时扔掉了一个剪枝,实际效果并不明显。那么当我们搜到答案的深度时仍然要面对一棵庞大的搜索树。

    由于IDFS第一次搜到答案时就可以直接退出,我们只需要让程序更快地搜到答案,即尽可能往答案所在的方向走。那么我们加一个IDA * 即可。

    设计估价函数。结合上面提到的下界,我们可以设计这样一个估价函数:

    [f(g[])=sum_{i=0}^{7}[g[ctr[i]]≠des[ctr[i]]] ]

    当当前深度加上预估值>当前最大深度时就没必要往下搜了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 
    using namespace std;
     
    const int pos[8][7]={{0,2,6,11,15,20,22},{1,3,8,12,17,21,23},{10,9,8,7,6,5,4},{19,18,17,16,15,14,13},{23,21,17,12,8,3,1},{22,20,15,11,6,2,0},{13,14,15,16,17,18,19},{4,5,6,7,8,9,10}};
    const int ctr[8]={6,7,8,11,12,15,16,17};
    const int a[9]={5,4,7,6,1,0,3,2,-1};
    int g[24]; bool flag;
    char op['L'+'z'+'s'];
     
    inline int evaluate(){
        int cnt[4]={0,0,0,0};
        for(register int i=0;i<8;i++) cnt[g[ctr[i]]]++;
        return 8-max(cnt[1],max(cnt[2],cnt[3]));
    }
    inline void change(const int &d){
        register int tmp=g[pos[d][0]];
        for(register int i=0;i<6;i++) g[pos[d][i]]=g[pos[d][i+1]];
        g[pos[d][6]]=tmp;
    }
    void IDAstar(int dep,int pre_dir,const int &maxdep){
        if(flag) return;
        if(dep>maxdep||dep+evaluate()>maxdep) return;
        if(!evaluate()){
            flag=true,op[dep]='';
            printf("%s
    %d
    ",op,g[ctr[0]]);
            return;
        }
        for(register int i=0;i<8;i++)if(i!=a[pre_dir]){
            change(i);
            op[dep]=i+'A';
            IDAstar(dep+1,i,maxdep);
            change(a[i]);
        }
    }
     
    int main(){
        while(0127){
            flag=false;
            for(register int i=0;i<24;i++){
                scanf("%d",&g[i]);
                if(!g[i]) return 0;
            }
            if(!evaluate()){ printf("No moves needed
    %d
    ",g[ctr[0]]); continue;}
            for(int maxdep=1;!flag;maxdep++) IDAstar(0,8,maxdep);
        }
    }
    
  • 相关阅读:
    Asp.net 默认配置下,Session莫名丢失的原因及解决办法
    回发或回调参数无效。在配置中使用 enableEventValidation=true或在页面中使用 启用了事件验证。
    SQL Server事务日志意外增大的处理方法
    SQLServer数据库设计表和字段(转)
    关于SQL Server数据库设计的感悟
    如何动手组建WiFi网络
    教你在SQL Server数据库中设计表和字段
    SQL Server数据库设计表和字段的经验
    SQL Server 的通用分页显示存储过程
    翻译: jQuery1.4官方文档
  • 原文地址:https://www.cnblogs.com/akura/p/10878028.html
Copyright © 2011-2022 走看看