博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 1324 Holedox Moving(A* + 状态设计 + 上界剪枝)
阅读量:4597 次
发布时间:2019-06-09

本文共 4763 字,大约阅读时间需要 15 分钟。

题意:

简单贪吃蛇问题,问最少经过多少步,贪吃蛇可以从点(1,1)出去。

思路:

1. 本题的状态设计,是一个难点所在:当头结点固定的时候,由于尾巴的长度最多不超过 7 节,每个结点又可以有上下左右四个方向(2位)移动,

   所以头结点处在 (x, y) 时,贪吃蛇的的状态可以用 7 * 2 = 14 位来表示,每个结点占 2 位;

2. 设计好状态之后另外一个难点就是,如果从 状态 -> 贪吃蛇坐标 的变换,其实就是涉及到一点位运算的知识,注意几个函数中上下左右的协调即可;

3. 通过 1,2 然后再采用宽搜,肯定能得到结果,不过会超时。这里采用启发式的搜索,估价函数为曼哈顿距离,其实提前用 bfs 预处理每个点到 (1, 1) 的最短路也是可以的;

4. 上面几点已经能够很好的 AC 了,不过还有更加值得优化的地方,找到贪吃蛇到达 (1, 1) 的最小最大距离,利用这个上界进行剪枝,又可以对时间有很高的飞跃;

5. 最终下面的代码跑到了 297ms 。其实还有很多可以优化的地方,因为本题的空间存在着很大的浪费,估价函数还可以进一步优化等等,有人是跑到了 0ms 的,所以还需努力.

 

#include 
#include
#include
using namespace std;bool vis[21][21][1<<14];bool stone[21][21];int row, col, L, K;const int dir[4][2] = {
-1, 0, 1, 0, 0, -1, 0, 1};struct Body {
int x, y;} body[10];struct ST {
int x, y, step, state, f; ST(int _x, int _y, int _step, int _state, int _f) : x(_x), y(_y), step(_step), state(_state), f(_f) {} bool operator < (const ST& other) const {
return f > other.f; }};void setstone() {
for (int i = 1; i < L; i++) stone[body[i].x][body[i].y] = true;}void clearstone() {
for (int i = 1; i < L; i++) stone[body[i].x][body[i].y] = false;}int getstate(int x, int y) {
int state = 0; for (int i = 1; i < L; i++) {
state <<= 2; if (body[i].x > body[i-1].x) // up state |= 0; else if (body[i].x < body[i-1].x) // down state |= 1; else if (body[i].y > body[i-1].y) // left state |= 2; else if (body[i].y < body[i-1].y) // right state |= 3; } return state;}void setbody(int x, int y, int state) {
const int MASK = 3; body[0].x = x, body[0].y = y; for (int i = 1; i < L; i++) {
int val = (state >> ((L-i-1)*2)) & MASK; body[i].x = body[i-1].x; body[i].y = body[i-1].y; if (val == 0) body[i].x += 1; else if (val == 1) body[i].x -= 1; else if (val == 2) body[i].y += 1; else if (val == 3) body[i].y -= 1; }}bool judge(int x, int y) {
if (0 < x && x <= row && 0 < y && y <= col && !stone[x][y]) {
return true; } return false;}inline int getdiff(int x, int y) {
return abs(x - 1) + abs(y - 1);}int astar() {
priority_queue
Q; int x = body[0].x, y = body[0].y; int state = getstate(x, y); int f = getdiff(x, y); Q.push(ST(x, y, 0, state, f)); vis[x][y][state] = true; while (!Q.empty()) {
ST u = Q.top(); Q.pop(); if (u.x == 1 && u.y == 1) return u.step; setbody(u.x, u.y, u.state); setstone(); for (int i = 0; i < 4; i++) {
x = u.x + dir[i][0]; y = u.y + dir[i][1]; state = (L<2) ? 0 : (u.state>>2) | (i<<((L-2)*2)); if (judge(x, y) && !vis[x][y][state]) {
vis[x][y][state] = true; f = u.step + 1 + getdiff(x, y); Q.push(ST(x, y, u.step + 1, state, f)); } } clearstone(); } return -1;}int bfs() {
bool visit[21][21]; memset(visit, false, sizeof(visit)); priority_queue
Q; int x = body[0].x, y = body[0].y; int f = getdiff(x, y); Q.push(ST(x, y, 0, 0, f)); visit[x][y] = true; while (!Q.empty()) {
ST u = Q.top(); Q.pop(); if (u.x == 1 && u.y == 1) return u.step; for (int i = 0; i < 4; i++) {
x = u.x + dir[i][0]; y = u.y + dir[i][1]; if (judge(x, y) && !visit[x][y]) {
visit[x][y] = true; f = u.step + 1 + getdiff(x, y); Q.push(ST(x, y, u.step + 1, 0, f)); } } } return -1;}int main() {
int cases = 0; while (scanf("%d%d%d", &row, &col, &L) && row && col && L) {
for (int i = 0; i < L; i++) scanf("%d%d", &body[i].x, &body[i].y); for (int i = 1; i <= row; i++) {
for (int j = 1; j <= col; j++) {
stone[i][j] = false; memset(vis[i][j], false, sizeof(vis[0][0])); } } scanf("%d", &K); for (int i = 0; i < K; i++) {
int x, y; scanf("%d%d", &x, &y); stone[x][y] = true; } int ans; int minstep = bfs(); setstone(); int maxstep = bfs(); clearstone(); if (minstep == -1) ans = -1; else if (minstep == maxstep) ans = minstep; else ans = astar(); printf("Case %d: %d\n", ++cases, ans); } return 0;}

转载于:https://www.cnblogs.com/kedebug/archive/2013/03/26/2983143.html

你可能感兴趣的文章
[iOS]数据库第三方框架FMDB详细讲解
查看>>
让IE6/IE7/IE8浏览器支持CSS3属性
查看>>
Windows 某些软件显示"口口"解决办法
查看>>
PHP+Hadoop+Hive+Thrift+Mysql实现数据统计分析
查看>>
和同事下班路上讨论心得(服务器部署的几点问题)
查看>>
Spring学习总结五——SpringIOC容器五
查看>>
解决多个ajax页面请求,页面loading阻塞问题
查看>>
Executor
查看>>
Javascript 表单验证对象控件 + ajax简单验证重复项与ajax提交数据
查看>>
使用抽象工厂设计一个简单的交易模块
查看>>
如何将广告始终定位到网页右下角
查看>>
常用js整理
查看>>
查看oracle/mysql数据库版本号
查看>>
memset函数
查看>>
使用postman+newman+python做接口自动化测试
查看>>
实体框架继承关系。很好
查看>>
201671010110 2016 2017 2《java程序设计》
查看>>
flask的基础认识
查看>>
静态blog的免费托管部署、加域名与搜索优化(SEO)
查看>>
oracle trunc(d1[,c1])
查看>>