当前位置: 代码迷 >> 综合 >> UVa 1343 The Rotation Game(IDA*)
  详细解决方案

UVa 1343 The Rotation Game(IDA*)

热度:78   发布时间:2023-09-23 09:43:22.0

主要是设计乐观估计函数来减枝

假设中心区域有6个2,2个3,那肯定是消掉3最好,毕竟就两个。

那么理想情况下,旋转一次就能把一个3变成2,那么最少操作2次。

我们用h()来计算最少还要操作几次,其原理是假设中心区域都放1或2或3,返回至少操作的次数中最小的数

maxd是假设最多能操作的数;

d是已经操作的数;

那么就可以得出乐观估计函数   h()+d>maxd  

其含义为 : 若  至少还要操作次数  加上  已经操作的次数  大于  最多总共操作的次数就退出 。


其次就是节点的处理了,编个号数组保存一下就方便多了。

给节点编号

                  A-0   B-1
                   00    01
                   02    03
H-7 04 05 06 07 08 09 10 C-2
                   11    12
G-6 13 14 15 16 17 18 19 D-3
                   20    21
                   22    23
                   F-5   E-4


#include<cstdio>
#include<algorithm>
using namespace std;
/*A-0	B-100    0102    03
H-7 04 05 06 07 08 09 10 C-211    12
G-6 13 14 15 16 17 18 19 D-320    2122    23F-5   E-4
*/
int line[8][7]={{0,2,6,11,15,20,22},   //A{1,3,8,12,17,21,23},   //B{10,9,8,7,6,5,4},      //C{19,18,17,16,15,14,13} //D
};
#define min3(x,y,z) min(min(x,y),z)
const int rev[]={5,4,7,6,1,0,3,2};   //保存对面的编号,如A-0条对面是F-5条,见上图 
const int center[]={6,7,8,12,17,16,15,11};  //中心区域点的编号 
const int maxn=1000+5;int a[24];
char ans[maxn];bool is_solved()   //观察是否完成任务 
{for(int i=0;i<8;i++)if(a[center[i]]!=a[center[0]]) return false;return true;
}
inline int diff(int n)    //中心区域有多少与n不同的数 ; 
{int cnt=0;for(int i=0;i<8;i++)if(a[center[i]]!=n) cnt++;return cnt;
}
inline int h()
{return min3(diff(1),diff(2),diff(3));  //如果中心区域要填满1,2,3,那么最少的不同数,即理想的操作数; 
}
void move(int k)
{int t=a[line[k][0]];for(int i=0;i<7-1;i++) a[line[k][i]]= a[line[k][i+1]];a[line[k][6]]=t;
}
bool dfs(int d,int maxd)
{if(d==maxd){if(is_solved()) {ans[d]='\0';printf("%s\n",ans);return true;}}else{if(h()+d>maxd) return false; for(int i=0;i<8;i++){ans[d]='A'+i;   //打印答案,因为是从A开始操作所以肯定是最小字典序 move(i);    //旋转第i条条子 if(dfs(d+1,maxd)) return true;move(rev[i]); //旋转第i条条子的反方向,即rev[i]条,恢复原位; }}return false;
}void solve()
{for(int maxd=1;;maxd++)if(dfs(0,maxd)) return;
}
int main()
{for(int i=4;i<8;i++) //填充E,F,G,H line,因为是有规律的就不人工初始化了; for(int j=0;j<7;j++)line[i][j]=line[rev[i]][6-j];while(scanf("%d",&a[0])==1&&a[0]){for(int i=1;i<24;i++) scanf("%d",&a[i]);if(is_solved()) printf("No moves needed\n");else solve();printf("%d\n",a[6]);}return 0;
}


  相关解决方案