标签:return 无法获得 false ida else 算法 题目 方式 重点
题目链接: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("\n%d\n",q[6]); } return 0; }
《算法竞赛进阶指南》0x28IDA* POJ2286 the rotation game
标签:return 无法获得 false ida else 算法 题目 方式 重点
原文地址:https://www.cnblogs.com/randy-lo/p/13175568.html