• 《算法竞赛进阶指南》0x28IDA* POJ2286 the rotation game


    题目链接:http://poj.org/problem?id=2286

    对于24个数组成的#,一共有8中拉的方式,求使得中间8个数相同的最小操作以及操作方式,由于一个结点扩展的分支有7个,所以朴素dfs将会在无法获得最优解的分支上花费太多时间

    通过枚举操作次数可以避免dfs搜索过深,并且加上未来估计,估计就是8-中间八个数中出现最多的数的出现次数(记做8-s),因为每次移动之后添加进一个新的数,移除的数可能是当前最多的数有可能是其他数

    所以至少还需要8-s次操作,如果当前操作+f()>max_depth,说明搜索不会成功,因为实际操作数一定是大于 当前操作数+估计的最小操作数的

    本题还有个重点就是保存每种操作的下标,便于循环移位,保存中间数的下标便于check是否是终态,保存每种操作的逆操作,便于回溯以及判断是否是还原了上次的操作(需要被舍弃).

    代码:

    /*
            0      1
            2     3
      4  5  6  7  8  9  10
            11    12
      13 14 15 16 17 18 19
              20    21
              22    23
    */
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxn 25
    
    int op[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}
    };
    //保存相反的操作 
    int opposite[8]={5,4,7,6,1,0,3,2};
    //中间的格子,判断是否一样的时候使用 
    int center[8]={6,7,8,11,12,15,16,17}; 
    
    int q[maxn];
    int path[100];
    int sum[4];
    
    int f(){        
        memset(sum,0,sizeof(sum));
        for(int i=0;i<8;i++)sum[q[center[i]]]++;
        int s=0;
        for(int i=1;i<=3;i++)s=max(s,sum[i]);
        return 8-s;
    }
    
    bool check(){
        for(int i=1;i<8;i++){
            if(q[center[i]]!=q[center[0]])return false;
        }
        return true;
    }
    
    void operate(int x){//循环移位 
        int tmp=q[op[x][0]];
        for(int i=0;i<6;i++){
            q[op[x][i]]=q[op[x][i+1]];
        }
        q[op[x][6]]=tmp;
    }
    
    bool dfs(int depth,int max_depth,int last){//不执行逆操作 
        if(depth+f() > max_depth)return false; 
        if(check())return true;
        
        for(int i=0;i<8;i++){
            if(opposite[i]==last)continue;//当前执行的操作是上一次的逆操作,放弃 
            operate(i);
            path[depth]=i;
            if(dfs(depth+1,max_depth,i))return true;
            operate(opposite[i]);//回溯,也就是执行逆操作 
        }
        
        return false;
    }
    
    int main(){
        while(scanf("%d",&q[0]) && q[0]){
            for(int i=1;i<24;i++)scanf("%d",&q[i]);
            
            int depth=0;
            while(!dfs(0,depth,-1))depth++;
            
            if(!depth)printf("No moves needed");
            else{
                for(int i=0;i<depth;i++)printf("%c",path[i]+'A');            
            }
            printf("
    %d
    ",q[6]);
        }    
        
        return 0;
    } 
  • 相关阅读:
    实时控制软件第四周作业
    实时控制软件第三次作业-编程作业(更新梯形加速并绘制轨迹)
    实时控制软件第三次作业(编程作业)-更新中
    实时控制软件设计第二周作业-停车场门禁控制系统状态机
    冰球游戏开发日志(四)
    冰球游戏开发日志(三)
    冰球项目开发日志(二)
    冰球项目开发日志(一)
    第四周作业
    第三周作业
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13175568.html
Copyright © 2020-2023  润新知