您的位置:首页 > 其它

The Rotation Game (UVA - 1343)

2017-05-05 20:06 344 查看


有个#字型的棋盘,2行2列,一共24个格。




如图:每个格子是1或2或3,一共8个1,8个2,8个3.


有A~H一共8种合法操作,比如A代表把A这一列向上移动一个,最上面的格会补到最下面。

求:使中心8个格子数字一致的最少步骤,要输出具体的操作步骤及最终中心区域的数字。如果有多个解,输出字典序最小的操作步骤。

解题思路:紫书上的题目,紫书上有两种解法,一种是重复三遍bfs,另一种是IDA*算法;

其实第二种方法代码更简短,第一种可能比较冗长。下面实现第二种,个人觉得第一种方法之要有那种思路就行,

我们重点掌握一下IDA*算法;

第2种方法:

IDA*算法的优势:与A*比起来,IDA*更实用:1.不需要判重,不需要排序;2.空间需求减少。

/*迭代加深算法是在dfs搜索算法的基础上逐步加深搜索的深度,它避免了广度优先搜索占用搜索空间太大的缺点,也减少了深度优先搜索的盲目性。它主要是在递归搜索函数的开头判断当前搜索的深度是否大于预定义的最大搜索深度,如果大于,就退出这一层的搜索,如果不大于,就继续进行搜索。这样最终获得的解必然是最优解。
 
而在A*算法中,我们通过使用合理的估价函数,然后在获得的子节点中选择fCost最小的节点进行扩展,以此完成搜索最优解的目的。但是A*算法中,需要维护关闭列表和开放列表,需要对扩展出来的节点进行检测,忽略已经进入到关闭列表中的节点(也就是所谓的“已经检测过的节点”),另外也要检测是否与待扩展的节点重复,如果重复进行相应的更新操作。所以A*算法主要的代价花在了状态检测和选择代价最小节点的排序上,这个过程中占用的内存是比较大的,一般为了提高效率都是使用hash进行重复状态检测。
 
而IDA*算法具有如下的特点:(
综合了A*算法的人工智能性和回溯法对空间的消耗较少的优点,在一些规模很大的搜索问题中会起意想不到的效果。它的具体名称是
Iterative Deepening A*, 1985年由Korf提出。该算法的最初目的是为了利用深度搜索的优势解决广度A*的空间问题,其代价是会产生重复搜索。归纳一下,IDA*的基本思路是:首先将初始状态结点的H值设为阈值maxH,然后进行深度优先搜索,搜索过程中忽略所有H值大于maxH的结点;如果没有找到解,则加大阈值maxH,再重复上述搜索,直到找到一个解。在保证H值的计算满足A*算法的要求下,可以证明找到的这个解一定是最优解。在程序实现上,IDA*
要比 A* 方便,因为不需要保存结点,不需要判重复,也不需要根据 H值对结点排序,占用空间小。 

而这里在IDA*算法中也使用合适的估价函数,来评估与目标状态的距离。

在一般的问题中是这样使用IDA*算法的,当前局面的估价函数值+当前的搜索深度 > 预定义的最大搜索深度时,就进行剪枝。
这个估计函数的选取没有统一的标准,找到合适的该函数并不容易,但是可以大致按照这个原则:在一定范围内加大各个状态启发函数值的差别。*/ (以上借鉴某位大神总结)
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int maxn,maxd;
int a[24];
char s[10000];
int zhong[9]={6,7,8,11,12,15,16,17}; // 中间八个点的位置
int h()
{
int yi,er,san;
yi = er = san = 0;
for(int i=0;i<8;i++)
{
if(a[zhong[i]]==1)yi++;
else if(a[zhong[i]]==2)er++;
else if(a[zhong[i]]==3)san++;
}
return 8 - max( max(yi,er), san ); //获得估价剩余步数
}
bool dfs(int k)
{
int cnt = h();
if(cnt==0){return true;}
if(k + cnt > maxd) return false; //剪枝
int t;
int tmp[24];
memcpy(tmp,a,sizeof(a));
//下面的8种情况可以用一个数组提前记下坐标,然后一个函数实现。这里这样更清楚。

4000
//A
t = a[0];
a[0]=a[2]; a[2]=a[6]; a[6]=a[11]; a[11]=a[15]; a[15]=a[20]; a[20]=a[22]; a[22]=t;
s[k] = 'A';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));

//B
t = a[1];
a[1] = a[3], a[3]=a[8], a[8]=a[12], a[12]=a[17], a[17]=a[21], a[21]=a[23], a[23]=t;
s[k] = 'B';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));

//C
t = a[10];
a[10]=a[9], a[9]=a[8], a[8]=a[7], a[7]=a[6], a[6]=a[5], a[5]=a[4], a[4]=t;
s[k] = 'C';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));

//D
t = a[19];
a[19]=a[18], a[18]=a[17], a[17]=a[16], a[16]=a[15], a[15]=a[14], a[14]=a[13], a[13]=t;
s[k] = 'D';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));
//E

t=a[23];
a[23]=a[21], a[21]=a[17],a[17]=a[12], a[12]=a[8], a[8]=a[3], a[3]=a[1], a[1]=t;
s[k] = 'E';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));

//F
t=a[22];
a[22]=a[20], a[20]=a[15], a[15]=a[11], a[11]=a[6], a[6]=a[2], a[2]=a[0], a[0]=t;
s[k] = 'F';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));
//G
t=a[13];
a[13]=a[14], a[14]=a[15], a[15]=a[16], a[16]=a[17], a[17]=a[18], a[18]=a[19], a[19]=t;
s[k] = 'G';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));

//HHHH
t=a[4];
a[4]=a[5], a[5]=a[6], a[6]=a[7], a[7]=a[8], a[8]=a[9], a[9]=a[10], a[10]=t;
s[k]='H';
if(dfs(k+1))return true;
memcpy(a,tmp,sizeof(tmp));

return false;
}
int main()
{
while(scanf("%d", &a[0])!=EOF)
{
if(a[0]==0)break;
maxn = maxd = 0;
memset(s,'\0', sizeof(s));
for(int i=1; i<24; i++) scanf("%d" ,&a[i]);
//for(int i=0;i<24;i++) printf("%d ",a[i]);
//cout << endl;
if(!h())
{
printf("No moves needed\n");
printf("%d\n",a[7]);
}
else
{
for(maxd=1; ;maxd++)
{
if(dfs(0))break;
}
for(int i=0; i<maxd; i++)
printf("%c",s[i]);

printf("\n%d\n",a[7]);
}

}
return 0;
}


水波
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  uva IDA