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 题目大意: 就是由于下大雨的时候约翰的农场就会被雨水给淹没,无奈下约翰不得不修建水沟,而且是网络 ...
随机推荐
- ZBrush软件中的笔触类型
在ZBrush® 中我们通过各种笔触类型,确定在使用ZBrush®画笔进行绘制时画笔的变化方式及状态.使用多种画笔绘制根据选择不同的笔触组合绘制,能够得到繁多变化丰富的制作效果. 选择笔触的类型 点击 ...
- 如何打开DOS控制台及常见DOS命令作用
如何打开DOS控制台? * A:xp下如何打开DOS控制台? * a:开始--程序--附件--命令提示符 * b:开始--运行--cmd--回车 * c:win+r--cmd- ...
- Anaconda3 安装报错 bunzip2: command not found
报错信息 Anaconda3-5.3.1-Linux-x86_64.sh: line 353: bunzip2: command not found tar: This does not look l ...
- sklearn学习8-----GridSearchCV(自动调参)
一.GridSearchCV介绍: 自动调参,适合小数据集.相当于写一堆循环,自己设定参数列表,一个一个试,找到最合适的参数.数据量大可以使用快速调优的方法-----坐标下降[贪心,拿当前对模型影响最 ...
- Python 爬虫练习: 爬取百度贴吧中的图片
背景:最近开始看一些Python爬虫相关的知识,就在网上找了一些简单已与练习的一些爬虫脚本 实现功能:1,读取用户想要爬取的贴吧 2,读取用户先要爬取某个贴吧的页数范围 3,爬取每个贴吧中用户输入的页 ...
- MVC设计模式与JavaWEB三层架构
一.MVC设计模式 MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controlle ...
- sql server 与 mysql在自定以数据类型的区别
sql server 中可以使用 create TYPE postal_code FORM varchar(6) not null; 用于限定邮编的数据位数,他基于varchar数据类型 注意: ...
- 创业笔记-Node.js入门之JavaScript与Node.js
JavaScript与Node.js JavaScript与你 抛开技术,我们先来聊聊你以及你和JavaScript的关系.本章的主要目的是想让你看看,对你而言是否有必要继续阅读后续章节的内容. 如果 ...
- WinServer-AD域控入门
计算机账户和用户账户的区别 域控中不需要事先建立计算机账户,但必须建立登录用户账户. 计算机只要知道域控管理员或者授权管理账户,就可以利用此账户为所有计算机加域. 计算机加域成功之后,都会在AD管理里 ...
- CODEVS——T 1269 匈牙利游戏 2012年CCC加拿大高中生信息学奥赛
http://codevs.cn/problem/1269/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Descript ...