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

Posted randy-lo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法竞赛进阶指南》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;
} 

 

以上是关于《算法竞赛进阶指南》0x28IDA* POJ2286 the rotation game的主要内容,如果未能解决你的问题,请参考以下文章

《算法竞赛进阶指南》0x43线段树 扫描线算法 POJ2482

《算法竞赛进阶指南》0x27A* 八数码问题 POJ1077

《算法竞赛进阶指南》0x15 POJ1961 KMPNext数组求循环节

《算法竞赛进阶指南》0x25广度优先搜索 POJ3322 Bloxorz I

《算法竞赛进阶指南》0x11栈 单调栈求矩形面积 POJ2559

《算法竞赛进阶指南》0x16Trie POJ3764异或最大路径