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

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

然后利用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. Spring Batch 高级-

    spring batch / 并行处理 / 多线程 分区 1. 并行处理,多线程,分区 http://blog.csdn.net/github_36849773/article/details/692 ...

  2. How to debug systemd step by step

    docker run -ti --name systemd --net host --privileged reg.docker.xxxxxxxx:latest /usr/lib/systemd/sy ...

  3. BZOJ 1856 [SCOI2010]生成字符串 (组合数)

    题目大意:给你n个1和m个0,你要用这些数字组成一个长度为n+m的串,对于任意一个位置k,要保证前k个数字中1的数量大于等于0的数量,求所有合法的串的数量 答案转化为所有方案数-不合法方案数 所有方案 ...

  4. [JZOJ]100046【NOIP2017提高A组模拟7.14】收集卡片

    Star 计划订购一本将要发行的周刊杂志,但他可不是为了读书,而是-- 集卡. 已知杂志将要发行 N 周(也就是 N 期),每期都会附赠一张卡片.Star 通 过种种途径,了解到 N 期杂志附赠的卡片 ...

  5. 八、frps服务端与nginx可共用80端口

    我的服务器,已经用nginx 做网站了,80端口只有一个,我还想我的frps一起使用,可以吗?这个是可以实现的,利用nginx的反向代理实现. 以下是在frps服务器上安装的nginx配置文件中设置的 ...

  6. php中mysqli 处理查询结果集总结

    在PHP开发中,我们经常会与数据库打交道.我们都知道,一般的数据处理操作流程为 接收表单数据 数据入库 //连接数据库 $link = mysqli_connect("my_host&quo ...

  7. os.getcwd()函数的用法

    获得当前路径 在Python中可以使用os.getcwd()函数获得当前的路径. 其原型如下所示: os.getcwd() 该函数不需要传递参数,它返回当前的目录.需要说明的是,当前目录并不是指脚本所 ...

  8. 为什么要重写toString()方法

    因为在System.out.println(类的对象名)时,类的对象名是个引用,如果不重写,就输出引用地址. 其实实际是这样的System.out.println(类的对象名.toString()), ...

  9. (转)Linux内核 TCP/IP、Socket参数调优

    Doc1: /proc/sys/net目录 所有的TCP/IP参数都位于/proc/sys/net目录下(请注意,对/proc/sys/net目录下内容的修改都是临时的,任何修改在系统重启后都会丢失) ...

  10. oracle用户锁定

    https://www.cnblogs.com/lostyue/archive/2011/12/06/2278063.html