题目大意:裸的八数码问题,让你输出空格的一条合法移动路径

首先利用康托展开对排列编号,可以预处理出排列,就不必逆展开了

然后利用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*算法)的更多相关文章

  1. 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]*( ...

  2. HDU 1043 Eight 八数码问题 A*算法(经典问题)

    HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...

  3. POJ-1077 HDU 1043 HDU 3567 Eight (BFS预处理+康拓展开)

    思路: 这三个题是一个比一个令人纠结呀. POJ-1077 爆搜可以过,94ms,注意不能用map就是了. #include<iostream> #include<stack> ...

  4. HDU 1043 Eight(八数码)

    HDU 1043 Eight(八数码) 00 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)   Problem Descr ...

  5. Eight POJ - 1077 HDU - 1043 八数码

    Eight POJ - 1077 HDU - 1043 八数码问题.用hash(康托展开)判重 bfs(TLE) #include<cstdio> #include<iostream ...

  6. HDU - 1043 - Eight / POJ - 1077 - Eight

    先上题目: Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  7. HDU 1043 八数码 Eight A*算法

    Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  8. ACM: HDU 1869 六度分离-Dijkstra算法

    HDU 1869六度分离 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Descri ...

  9. HDU 1532 (Dinic算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532 题目大意: 就是由于下大雨的时候约翰的农场就会被雨水给淹没,无奈下约翰不得不修建水沟,而且是网络 ...

随机推荐

  1. Linux中删除特殊符号文件名文件

    Linux 系统下的文件名长度最多可到256个字符.通常情况下,文件名的字符包括:字母.数字.“.”(点).“_”(下划线)和“-”(连字符). Linux 允许在文件名中使用除上述符号之外的其它符号 ...

  2. Pyhton学习——Day25

    #面向对象的几个方法#1.静态方法@staticmethod,不能访问类属性,也不能访问实例属性,只是类的工具包#2.类方法:@classmethod,在函数属性前加上类方法,显示为(cls)代表类, ...

  3. jquery.nicescroll.min.js滚动条插件的用法

    1.jquery.nicescroll.min.js源码 /* jquery.nicescroll 3.6.8 InuYaksa*2015 MIT http://nicescroll.areaaper ...

  4. laravel 授权、用户验证

    记录帖 一.授权 只允许管理员删除用户,给管理员授权时,可以这样做,首先: 创建UserPolicy类: php artisan make:policy UserPolicy  然后在UserPoli ...

  5. 基于LXC的虚拟网络自动部署

    一.问题: 在搭建以LXC为基础的虚拟网络时,网络参数繁多,配置过程繁琐.面临一个新的网络拓扑结构时,通常要花费大量时间来构建网络.因此,如果能通过配置文件,自动生成相对应的网络拓扑,并生成操作指令. ...

  6. 接口测试及接口Jmeter工具介绍

    一.接口类型及数据传递的格式 接口类型: 1.HTTP接口:通过GET或POST来获取数据,在数据处理上效率比较高 2.WebServer接口:通过SOAP协议来获取数据,比起http来说处理更加复杂 ...

  7. 【codeforces 812C】Sagheer and Nubian Market

    [题目链接]:http://codeforces.com/contest/812/problem/C [题意] 给你n个物品; 你可以选购k个物品;则 每个物品有一个基础价值; 然后还有一个附加价值; ...

  8. Springboot 应用启动分析

    https://blog.csdn.net/hengyunabc/article/details/50120001#comments 一,spring boot quick start 在spring ...

  9. java用freemarker实现导出excel

    前几天做了jxl导出excel,现在用freemarker做一下 freemarker导出excel和导出word步骤和是实现方法是相同的. 1.制作excel模板 2.将后缀名改为ftl,放到对应的 ...

  10. 轻松学习JavaScript十七:JavaScript的BOM学习(二)

    JavaScript计时事件 通过使用JavaScript中的BOM对象中的window对象的两个方法就是setTimeout()方法和claerTimeout()方法,我们 有能力作到在一个设定的时 ...