HDU 1043 Eight (A*算法)
题目大意:裸的八数码问题,让你输出空格的一条合法移动路径
首先利用康托展开对排列编号,可以预处理出排列,就不必逆展开了
然后利用A*算法求解
A*算法是一种启发式搜索,具体实现要用到优先队列/堆,不同于$dijkstra$,它的堆不是按照 初始状态向当前状态的花费$dis_{i}$进行贪心转移,而是额外处理出一个估值函数,处理出当前状态到目标状态花费的估计值$h_{i}$,然后按照$dis_{i}+h_{i}$排序,优先取出总和最小的。并且每个状态只会被搜索一次。如果搜索到了目标状态,立即跳出
这个过程,相当于我们取出一个全局较优解,虽然不一定是最优的,但大量减少了无用的搜索时间
而这道题的估值函数,可以粗略的计算为,每个数 当前状态的位置 到 目标状态的位置 的曼哈顿距离$(|xj-xi|+|yj-yi|)$ 之和
经过了A*优化的搜索,虽然不一定能搜出最短的路径,但极大减少了搜索的时间,因为搜的路径越短,我们搜索的总时间也越短,几乎是指数级别的优化。
然而A*也有弊端,如果存在无解的情况,A*就会退化成BFS,对所有状态都搜一次,而且多了一个常数$log$,在hdu上会T掉
所以我上网查了用了八数码判无解的方法,即对于去掉空格以后的8个数的排列,如果逆序对数量总和是奇数,则无解
证明大概是这样的,对于一个序列,任意交换两个相邻的数,逆序对数量的奇偶性不变,而八数码的表格扔到序列上,也满足这个性质
搞了大半个下午终于过了
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define NN 370010
#define MM 100
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define inf 0x3f3f3f3f
using namespace std; struct node{
int id,d;
friend bool operator<(const node &s1,const node &s2)
{return s1.d>s2.d;}
node(int id,int d):id(id),d(d){}
node(){}
};
int xx[]={-,,,},yy[]={,,,-};
int f[NN][],vis[NN],p[][],cnt;
int h[NN],g[NN],fa[NN],d[NN];
int S[],use[],now[],tmp[],mu[];
inline int mabs(int x){return x>=?x:-x;}
char ans[MM],c[]={'u','r','d','l'}; void dfs_permu(int dep)
{
if(dep==){
cnt++;
for(int i=;i<=;i++)
f[cnt][i]=now[i],
h[cnt]+=(mabs((i-)/-(now[i]-)/)+mabs((i-)%-(now[i]-)%));
return;
}
for(int i=;i<=;i++)
if(!use[i]){
use[i]=,now[dep]=i;
dfs_permu(dep+);
use[i]=,now[dep]=;
}
}
bool check(int x,int y)
{if(x<||y<||x>||y>)return ;return ;}
void Pre()
{
dfs_permu();
mu[]=;
for(int i=;i<=;i++)
mu[i]=mu[i-]*i;
}
int s[];
void update(int x,int w){for(int i=x;i<=;i+=(i&(-i)))s[i]+=w;}
int query(int x){int ans=;for(int i=x;i>;i-=(i&(-i)))ans+=s[i];return ans;}
int canter(int *tmp)
{
int ans=;
for(int i=;i<=;i++)
update(i,);
for(int i=;i<=;i++){
ans+=query(tmp[i]-)*mu[-i];
update(tmp[i],-);
}
return ans+;
}
int clr[NN],nn;
void init()
{
memset(ans,,sizeof(ans));
for(int i=;i<=nn;i++){
vis[clr[i]]=fa[clr[i]]=d[clr[i]]=;
g[clr[i]]=inf;
}nn=;
} int main()
{
Pre();
char str[];
priority_queue<node>q;
nn=cnt;
for(int i=;i<=nn;i++) clr[i]=i;
while(scanf("%s",str)!=EOF)
{ if(''<=str[]&&str[]<='')
S[]=str[]-'';
else S[]=;
for(int i=;i<=;i++)
{
scanf("%s",str);
if(''<=str[]&&str[]<='')
S[i]=str[]-'';
else S[i]=;
}
int invcnt=;
for(int i=;i<=;i++)
for(int j=;j<i;j++){
if(S[i]==||S[j]==) continue;
if(S[j]>S[i]) invcnt++;
}
if(invcnt&){
printf("unsolvable\n");
continue;}
init();
int s,t,st,sx,sy,x,y;
st=canter(S);
if(st==){
puts("");
continue;
}
q.push(node(st,h[st]));
g[st]=;
while(!q.empty())
{
node k=q.top();q.pop();
s=k.id;clr[++nn]=s;
if(s==) break;
if(vis[s]) continue; vis[s]=;
for(int i=;i<=;i++)
if(f[s][i]==)
sx=(i-)/+,sy=(i-)%+;
for(int i=;i<=;i++)
tmp[i]=f[s][i];
for(int k=;k<;k++)
{
x=sx+xx[k],y=sy+yy[k];
if(!check(x,y)) continue;
swap(tmp[(x-)*+y],tmp[(sx-)*+sy]);
int t=canter(tmp);
if(g[t]>g[s]+&&!vis[t]){
g[t]=g[s]+,fa[t]=s,d[t]=k;
q.push(node(t,g[t]+h[t]));
}
swap(tmp[(x-)*+y],tmp[(sx-)*+sy]);
}
}
while(!q.empty()){
node k=q.top();q.pop();
s=k.id;clr[++nn]=s;
}
if(!fa[]){
printf("unsolvable\n");
continue;
}
t=;int num=;
while(t!=st){
ans[++num]=c[d[t]];
t=fa[t];
}
for(int i=num;i>=;i--)
printf("%c",ans[i]);
puts(""); } return ;
}
HDU 1043 Eight (A*算法)的更多相关文章
- POJ 1077 && HDU 1043 Eight A*算法,bfs,康托展开,hash 难度:3
http://poj.org/problem?id=1077 http://acm.hdu.edu.cn/showproblem.php?pid=1043 X=a[n]*(n-1)!+a[n-1]*( ...
- HDU 1043 Eight 八数码问题 A*算法(经典问题)
HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...
- POJ-1077 HDU 1043 HDU 3567 Eight (BFS预处理+康拓展开)
思路: 这三个题是一个比一个令人纠结呀. POJ-1077 爆搜可以过,94ms,注意不能用map就是了. #include<iostream> #include<stack> ...
- HDU 1043 Eight(八数码)
HDU 1043 Eight(八数码) 00 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Descr ...
- Eight POJ - 1077 HDU - 1043 八数码
Eight POJ - 1077 HDU - 1043 八数码问题.用hash(康托展开)判重 bfs(TLE) #include<cstdio> #include<iostream ...
- HDU - 1043 - Eight / POJ - 1077 - Eight
先上题目: Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- HDU 1043 八数码 Eight A*算法
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- ACM: HDU 1869 六度分离-Dijkstra算法
HDU 1869六度分离 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Descri ...
- HDU 1532 (Dinic算法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532 题目大意: 就是由于下大雨的时候约翰的农场就会被雨水给淹没,无奈下约翰不得不修建水沟,而且是网络 ...
随机推荐
- Java数据库开发
Nosql数据库使用场景 首先需要确认一个问题,nosql能做什么?在现在的开发领域中nosql可以实现文档存储(BSON.JSON).缓存存储.图像缓存(图像搜索),但是对于nosql的具体应用场景 ...
- Eclipse中使用GIT提交文件至本地
GIT提交文件至本地: 1. 右击项目——Team——Commit…: 2.在弹出的Commit Changes框中——选择要提交的文件——填写提交说明——点击Commit,即可提交至本地.
- IOS-iOS 8 : Location Services not working(iOS 8 定位应用定位失败)
如果是xcode6和ios 8的话,需要调用 CLLocationManager requestAlwaysAuthorization 方法,具体步骤如下: 1. @interface里: CLLoc ...
- 【HNOI】合唱队
[HNOI]合唱队 题意 对于一个初始序列,保证两两不同,通过一些变换得到目标序列: 第一个值直接插入空的当前队列 对于从第二个值开始的每个值 如果原序列中 $ a[i] $,若 $ a[i]> ...
- Python多环境扩展管理
Python发展至今,版本众多,在使用过程中经常遇到第三方库依赖的Python版本和系统Python版本不一致的情况.同时又因系统底层需调用当前版本Python,所以不能随意变更当前系统Python版 ...
- 洛谷P5238 整数校验器
看到没有边读入边处理的,我来水一发 我们要看一下有那些情况是格式不合法的 单独的负号 -0(后面可以有其他数字) 0 +(后面一些数字) 我们用快速读入的方法 读取字符进行处理 还有可能超出范围的 考 ...
- Android学习之GridView图片布局适配经验
開始解说这篇博客之前,我想问一下,当布局相似GridView这样的多列布局时,我们该怎么布局,才干更好的去适配呢? 扣张图来展示一下 比如这样的需求,三张图片均分屏幕 实现方法: 1.切图固定,比如是 ...
- Android知识点总结
说明 当中大部分文章都是转载自其它大神之手.在转载的过程中学到了非常多,这里主要解说的是android体系的相关知识点,本文会持续更新. 1 Android service相关知识点 Android ...
- PHP中用下标符号[]去读取字符串的逻辑
PHP中 [(下标)] 符号不仅能够应用于数组和对象,还能够应用于字符串,假设不注意非常easy出错. 比方获取一个网络接口,正常情况下会返回一个数组结构的json,经过解析之后结果为: array( ...
- m_Orchestrate learning system---十、解决bug最根本的操作是什么
m_Orchestrate learning system---十.解决bug最根本的操作是什么 一.总结 一句话总结:多学多练,遇到bug超级轻松 1.如何查看js代码的异常? 开发者选项里面可以查 ...