Eight
Eight
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043/http://acm.split.hdu.edu.cn/showproblem.php?pid=1043
IDA*
八数码问题直接dfs/bfs,时间复杂度很高,需要一个很好的剪枝,使用IDA*。当前状态到达目标状态最短(理想)距离h是各个数字直接到达目的地,如果h+当前步数>最深搜索的步数,那么这种情况就不去考虑。对于判断八数码是否可解,需要用到逆序数的知识((╯‵□′)╯︵┻━┻这谁会知道啊):x的移动并不影响整个数列逆序数的奇偶性,也就是说若给定初始状态逆序数的奇偶性与目标状态不同,则unsolvable。去重用到了状态压缩,因为数字数量级为10^9,使用set/map存储状态。(坑点是多组数据,但是题目没说)
代码如下:
#include<cstdio>
#include<cmath>
#include<iostream>
#include<set>
using namespace std;
const int standard=;
set<int>exist;
int a[],state[][],deep,sx,sy,step[];
char c;
int dx[]={,,-,};
int dy[]={-,,,};
char towards[]={'l','r','u','d'};
int index;
bool ok=;
int inversions(){//求逆序数
int num=;
for(int i=;i<;++i)
for(int j=i+;j<;++j)
if(a[i]!=&&a[j]!=)
if(a[j]<a[i])num++;
return num;
}
int zip(){
int s=;
for(int i=;i<;++i)
for(int j=;j<;++j)
s=s*+state[i][j];
return s;
}
int Astar(){//无视障碍物直接到达目的地所需步数
int h=;
for(int i=;i<;++i)
for(int j=;j<;++j){
int num=state[i][j];
if(num!=){
int x=(num-)/;
int y=(num-)%;
h+=abs(x-i)+abs(y-j);
}
}
return h;
}
void IDAstar(int px,int py,int nowdeep){
if(ok)return;
int h=Astar();
if(!h&&zip()==standard){
ok=;
return;
}
if(nowdeep+h>deep)return;//A*估价函数
for(int i=;i<;++i){
int x=px+dx[i];
int y=py+dy[i];
if(<=x&&x<&&<=y&&y<){
swap(state[px][py],state[x][y]);
int s=zip();
if(!exist.count(s)){
step[index++]=i;
exist.insert(s);
IDAstar(x,y,nowdeep+);
if(ok)return;
exist.erase(s);
step[--index]=;
}
swap(state[px][py],state[x][y]);
}
}
}
int main(void){
char k;
while(cin>>k){
ok=;
index=;
for(int i=;i<;++i){
if(i==)c=k;
else cin>>c;
if(''<=c&&c<='')
a[i]=c-'';
else a[i]=;
}
if(inversions()&){//若有解,逆序数的奇偶性和standard相同
cout<<"unsolvable"<<endl;
continue;
}
for(int i=;i<;++i)
for(int j=;j<;++j){
state[i][j]=a[*i+j];
if(state[i][j]==)
sx=i,sy=j;
}
int s=zip();
if(s==standard){
cout<<""<<endl;
continue;
}
for(deep=;!ok;++deep){
exist.clear();
exist.insert(s);
IDAstar(sx,sy,);
}
for(int i=;i<index;++i)
cout<<towards[step[i]];
cout<<""<<endl;
}
}
随机推荐
- 我的 MarkDown 学习笔记
MarkDown 一种用于写作的轻量级[标记语言].它用简洁的语法代替排版,而不像一般的文字处理软件 Word 或者 Pages 有大量的排版.字体设置等. 如果你对文章的样式没有太多要求,只注重写文 ...
- 【CSS学习笔记】初始化CSS后,写li,并利用背景图片,来完成li小图标的效果,且达到个浏览器兼容
第一种情况 /*当标题前的图标时单独的一个点儿或者方块或者其他类似图标时,定义背景图background要放在<li>里. 在<li>中设置背景图片的尺寸,地址,不重复, ...
- 删除style的样式JQuery
有些页面样式不规范,没有写在一个class里,例如:<div id="show" style="width:100px; padding-top:10px; f ...
- Appium同时运行多个设备
为了提高测试效率,测试需要同时在多个android设备上运行,就需要启动多个appium. 启动appium时,为每个设备设置不同的端口号,并为driver设置该设备的udid.见如下实例,关键是红色 ...
- Android Tips
(1).设置图片缓存大小,一般可以设置为内存的1/8 int memoryCache = (int) (Runtime.getRuntime().maxMemory() / 8); (2). (3). ...
- Linux学习-文件和目录管理
Linux文件和目录管理 文件系统架构 1.Linux文件系统具有层级性 1)文件或者目录起始于根目录"/"成为树状结构 2)最顶层由/开始 2 ...
- C# 利用ajax实现局部刷新
C#所有runat="server"的控件都会造成整个界面的刷新,如果想实现局部刷新,可以利用ajax. 需要加入的控件有ScriptManager和UpdatePanel,可以实 ...
- Elasticsearch 5.0 安装 Search Guard 5 插件 (五)
一.Search Guard 简介 Search Guard 是 Elasticsearch 的安全插件.它为后端系统(如LDAP或Kerberos)提供身份验证和授权,并向Elasticsearc ...
- emacs 使用教程
http://www.cnblogs.com/liuchaogege/p/4464211.html
- FZU 2086 餐厅点餐(模拟)
Problem 2086 餐厅点餐 Problem Description Jack最近喜欢到学校餐厅吃饭,好吃干净还便宜. 在学校餐厅,有a种汤,b种饭,c种面条,d种荤菜,e种素菜. 为了保证膳食 ...