HDU - 1043 A* + 康托 [kuangbin带你飞]专题二
这题我第一次用的bfs + ELFhash,直接TLE,又换成bfs + 康托还是TLE,5000ms都过不了!!我一直调试,还是TLE,我才发觉应该是方法的问题。
今天早上起床怒学了一波A*算法,因为IDA*我很熟悉,因此A*也学得很快,曼哈顿距离也很容易理解,看了好多人都用的A*过掉的。我一直在想A*算法无法保证得到最短路啊,怎么能AC?我擦,后来一读题目,题目没说要最短路径啊,只要任意一条路就可以了。我就呵呵了,愤怒写了一波A*过掉。
思路:
1. 根据逆序数可以判断是否有解,如果当前逆序数为奇数一定无解,是偶数则进行搜索。
2. 利用康拓判重。
3. 启发函数 : F = G + H. A*算法的精髓, G表示从初始状态到达当前状态的花费,H表示当前状态到达目标状态的花费,H只能大概估计,估计可用曼哈顿距离。曼哈顿距离介绍
AC代码
#include<cstdio> #include<queue> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int maxn = 4e5 + 5; int vis[maxn]; //close表用于判重 int goal[] = {1,2,3,4,5,6,7,8,0}; int st[9]; typedef int state[9]; struct node{ int a[9]; int g, h; // 估价函数 int ha, pos; node() { } node(int *b, int g, int h, int ha, int pos):g(g), h(h), ha(ha), pos(pos){ memcpy(a, b, sizeof(a)); } bool operator < (const node &p) const { return h > p.h || (p.h == h && g > p.g); // h小在前,g小在前 } }; struct Node{ int pre; char dir; }Pre[maxn]; const int dx[] = {0,0,-1,1}; const int dy[] = {1,-1,0,0}; const char dir[] = {'r','l','u','d'}; int fact[9]; void deal() { //1~8阶乘打表,方便编码 fact[0] = 1; for(int i = 1; i < 9; ++i) fact[i] = fact[i - 1] * i; } int cut(int *a) { int cnt = 0; for(int i = 0; i < 9; ++i) { if(a[i] == 0) continue; for(int j = i + 1; j < 9; ++j) { if(a[j] != 0 && a[i] < a[j]) ++cnt; } } return cnt; } int KT(int *a) { int code = 0; for(int i = 0; i < 9; ++i) { int cnt = 0; for(int j = i + 1; j < 9; ++j) if(a[j] < a[i]) cnt++; code += fact[8 - i] * cnt; } return code; } void print(int u) { if(Pre[u].pre == -1) return; print(Pre[u].pre); printf("%c", Pre[u].dir); } int get_h(int *a) { //根据曼哈顿距离得到的估价函数 int cnt = 0; for(int i = 0; i < 9; ++i) { if(!a[i]) continue; int x = (a[i] - 1) / 3, y = (a[i] - 1) % 3; //终点的position cnt += abs(i / 3 - x) + abs(i % 3 - y); } return cnt; } int Astar() { priority_queue<node>q; int des = KT(goal); //目标 memset(vis, 0, sizeof(vis)); int code = KT(st); vis[code] = 1; Pre[code].dir = 'x'; Pre[code].pre = -1; int pos; for(int i = 0; i < 9; ++i) if(!st[i]) pos = i; int g = 0, h = get_h(st); q.push(node(st, g, h, code, pos)); while(!q.empty()) { node p = q.top(); q.pop(); code = p.ha, g = p.g, h = p.h, pos = p.pos; if(code == des) { // 找到答案 //printf("%d\n", g); print(des); return 1; } state &a = p.a; int x = pos / 3, y = pos % 3; for(int i = 0; i < 4; ++i) { int px = x + dx[i], py = y + dy[i]; if(px < 0 || py < 0 || px >= 3 || py >= 3) continue; int pz = px * 3 + py; swap(a[pos], a[pz]); int code1 = KT(a); if(vis[code1]) { swap(a[pos], a[pz]); continue; } vis[code1] = 1; Pre[code1].dir = dir[i]; Pre[code1].pre = code; q.push(node(a, g + 1, get_h(a), code1, pz)); swap(a[pos], a[pz]); } } return -1; } int main() { deal(); char str[50]; while(fgets(str, sizeof(str), stdin) != NULL) { int ind = 0; for(int i = 0; str[i] != '\n'; ++i) { if(str[i] == 'x') st[ind++] = 0; else if(str[i] >= '0' && str[i] <= '9') st[ind++] = str[i] - '0'; } // 根据逆序数提前判定是否有解 //for(int i = 0; i < 9; ++i) printf("%d ", st[i]); if(cut(st) % 2 == 1) { printf("unsolvable\n"); continue; } if( Astar() == -1) printf("unsolvable"); printf("\n"); } return 0; }
如有不当之处欢迎指出!
HDU - 1043 A* + 康托 [kuangbin带你飞]专题二的更多相关文章
- HDU - 3567 Eight II (bfs预处理 + 康托) [kuangbin带你飞]专题二
类似HDU1430,不过本题需要枚举X的九个位置,分别保存状态,因为要保证最少步数.要保证字典序最小的话,在扩展节点时,方向顺序为:down, left, right, up. 我用c++提交1500 ...
- HDU - 3567 IDA* + 曼哈顿距离 + 康托 [kuangbin带你飞]专题二
这题难度颇大啊,TLE一天了,测试数据组数太多了.双向广度优先搜索不能得到字典序最小的,一直WA. 思路:利用IDA*算法,当前状态到达目标状态的可能最小步数就是曼哈顿距离,用于搜索中的剪枝.下次搜索 ...
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
- HDU - 3001 Travelling 状压dp + 三进制 [kuangbin带你飞]专题二
终于刷完搜索专题了. 题意:给定n个城市,每个城市参观不能超过两次,两个城市之间有道路通过需要花费X,求通过能所有城市的最小花费. 思路:每个城市有三个状态0,1,2,可用三进制存储所有城市的访问状态 ...
- HDU - 3533 bfs [kuangbin带你飞]专题二
看了好久的样例才看懂. 题意:有一个人要从(0,0)走到(n,m),图中有k个碉堡,每个碉堡可以向某个固定的方向每隔t秒放一次炮,炮弹不能穿越另一个碉堡,会被阻挡.人在移动的过程中不会被炮弹打到,也就 ...
- HDU - 3085 双向BFS + 技巧处理 [kuangbin带你飞]专题二
题意:有两只鬼,一个男孩女孩被困在迷宫中,男孩每秒可以走三步,女孩只能1步,鬼可以两步且可以通过墙.问男孩女孩是否可以在鬼抓住他们之前会合? 注意:每秒开始鬼先移动,然后两人开始移动. 思路:以男孩和 ...
- HDU - 1067 Gap (bfs + hash) [kuangbin带你飞]专题二
题意: 起初定28张卡牌的排列,把其中11, 21, 31, 41移动到第一列,然后就出现四个空白,每个空白可以用它的前面一个数的下一个数填充,例如43后面的空格可以用44填充,但是47后面即 ...
- HDU - 2102 A计划 (BFS) [kuangbin带你飞]专题二
思路:接BFS判断能否在限制时间内到达公主的位置,注意如果骑士进入传送机就会被立即传送到另一层,不会能再向四周移动了,例如第一层的位置(x, y, 1)是传送机,第二层(x, y, 2)也是传送机,这 ...
- HDU - 2181 dfs [kuangbin带你飞]专题二
保存每个节点的下一个节点一直往下面走就行了,不能重复经过某个点,当经过的点达到20个而且当前节点的下一个节点是起点就打印答案. AC代码 #include<cstdio> #include ...
随机推荐
- 搭建Hadoop集群(centos6.7+hadoop-2.7.3)
hadoop集群有三种运行模式:单机模式.伪分布模式.完全分布模式.我们这里搭建第三种完全分布模式,即使用分布式系统,在多个节点上运行. 1 环境准备 1.1 配置DNS 进入配置文件,添加主节点和从 ...
- BFC(块级格式上下文)
BFC的生成 满足下列css声明之一的元素便会生成BFC 根元素 float的值不为none overflow的值不为visible display的值为inline-block.table-cell ...
- MyEclipse中设置注释模板的方法
1.选择菜单Window→Preferences. 2.选择Java→Code style→Code Templates→Commets.选中具体的分类如Methods,点击右侧的Edit可以设置对应 ...
- 优秀的基于VUE移动端UI框架合集
1. vonic 一个基于 vue.js 和 ionic 样式的 UI 框架,用于快速构建移动端单页应用,很简约,是我喜欢的风格 star 2.3k 中文文档 在线预览 2.vux 基于WeUI和Vu ...
- Git分支管理[三]
标签(linux): git 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 git分支管理命令 git branch #创建分支 git branch -v # ...
- smokeping一键安装脚本
#!/bin/bash #Date 2017/11/11 #mail caoyf1992@163.com [ $(id -u) != "0" ] && echo & ...
- 极其蛋疼的if else 中的break用法
主要原因是if不是循环语句 像这样的: while(...) { ==res) { break; } printf("A"); } 跳出的就是while循环.而不是if判断语句 补 ...
- PHP操作Memcached的方法汇总
memcached非关系型数据库安装.php中的memcache的扩展安装.以及php中的memcached的扩展安装可以参考: http://www.cnblogs.com/phpstudy2015 ...
- CSS3动画详解(超详细)
本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. 前言 本文主要内容: 过渡:transition 2D 转换 trans ...
- Windows实用命令
Windows实用命令 # 统计ESTABLISHED状态下的连接一共有多少个/c是统计行数,/i是忽略大小写 netstat -ano|find /i "established&qu ...