题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043

思路分析:

<1> 搜索算法: A*算法, Heuristic函数:曼哈顿距离

<2> 剪枝技巧: 如果8数码问题中的初始状态的逆序数为奇数(除了’x’),则不存在解;否则,存在解;

代码如下:

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std; const int MAX_N = + ;
int map[];
bool close[MAX_N];
char dir[MAX_N], direction[] = "udlr";
int open[MAX_N], pa[MAX_N], f[MAX_N];
const int FACT[] = {, , , , , , , , };
const int MOVE[][] = {{, -}, {, }, {-, }, {, }}; struct Node
{
int id;
int f, g, h;
int flags; // 表示该状态被松弛次数
Node() {}
Node(int a_id, int a_g, int a_h, int a_flags)
{
id = a_id, g = a_g, h = a_h, flags = a_flags;
f = g + h;
}
friend bool operator<(const Node &lhs, const Node &rhs);
};
bool operator<(const Node &lhs, const Node &rhs) { return lhs.f > rhs.f; }
priority_queue<Node> find_min; int StateToCanto()
{
int state_num = ;
for (int i = ; i < ; ++i)
{
int temp = map[i] - ; for (int j = ; j < i; ++j)
temp -= (map[j] < map[i]);
state_num += temp * FACT[ - i];
}
return state_num;
} int StateToId()
{
int ans = ; for (int i = ; i < ; ++i)
ans = ans * + map[i];
return ans;
} void IdToState(int num)
{
int i = ;
while (num)
{
map[i--] = num % ;
num /= ;
}
} int Heuristic()
{
int sum = ;
for (int i = ; i < ; i++)
for (int j = ; j < ; j++)
{
int k = i * + j;
if (map[k] == ) continue;
sum += abs(i - (map[k] - ) / ) + abs(j - (map[k] - ) % );
}
return sum;
} inline bool inversionNumberCheck()
{
int cnt = ;
for (int i = ; i < ; ++i)
{
if (map[i] == ) continue;
for (int k = i - ; k >= ; --k)
{
if (map[k] == ) continue;
if (map[k] > map[i])
cnt++;
}
}
return cnt & ;
} void FindX(int &x, int &y)
{
for (int i = ; i < ; ++i)
{
if (map[i] == )
{
y = i / ;
x = i % ;
return;
}
}
} int A_star()
{
int state_canto, state_id; state_canto = StateToCanto();
state_id = StateToId();
open[state_canto] += ;
Node start(state_id, , Heuristic(), open[state_canto]);
f[state_canto] = start.f;
find_min.push(start);
pa[state_canto] = -;
dir[state_canto] = ''; if (state_id == )
return state_canto; while (!find_min.empty())
{
Node parent = find_min.top();
Node child;
int p_x, p_y, c_x, c_y, parent_canto;
find_min.pop(); IdToState(parent.id);
parent_canto = StateToCanto();
if (parent.flags != open[parent_canto]) // 一个状态可能被松弛多次,检测parent是否为该状态最后一次松弛的状态
continue;
close[StateToCanto()] = ; // To do FindX(p_x, p_y);
for (int i = ; i < ; ++i)
{
int temp_swap, child_state_conto; c_x = p_x;
c_y = p_y;
c_x += MOVE[i][];
c_y += MOVE[i][]; if (c_x < || c_x >= || c_y < || c_y >= )
continue;
temp_swap = map[p_x + p_y * ];
map[p_x + p_y * ] = map[c_x + c_y * ];
map[c_x + c_y * ] = temp_swap;
child_state_conto = StateToCanto(); if (close[child_state_conto] == )
{
temp_swap = map[p_x + p_y * ];
map[p_x + p_y * ] = map[c_x + c_y * ];
map[c_x + c_y * ] = temp_swap; continue;
} child.id = StateToId();
if (child.id == )
{
pa[child_state_conto] = parent_canto;
dir[child_state_conto] = direction[i];
return child_state_conto;
} child.h = Heuristic();
child.g = parent.g + ;
child.f = child.g + child.h;
child.flags = open[child_state_conto] + ;
pa[child_state_conto] = parent_canto;
dir[child_state_conto] = direction[i];
if (open[child_state_conto] == || f[child_state_conto] > child.f)
{
f[child_state_conto] = child.f;
open[child_state_conto] = child.flags;
find_min.push(child);
}
temp_swap = map[p_x + p_y * ];
map[p_x + p_y * ] = map[c_x + c_y * ];
map[c_x + c_y * ] = temp_swap;
}
}
return -;
} void Find(int i)
{
if (pa[i] == -)
return;
else
{
Find(pa[i]);
printf("%c", dir[i]);
}
} void PrintPath()
{
int end_canto; for (int i = ; i < ; ++i)
map[i] = i + ;
end_canto = StateToCanto(); Find(end_canto);
printf("\n");
} int main()
{
int ans = ; while (scanf("%s", &map[]) != EOF)
{
map[] = (map[] == 'x' ? : (map[] -= ''));
for (int i = ; i < ; ++i)
{
scanf("%s", &map[i]);
map[i] = (map[i] == 'x' ? : (map[i] -= ''));
} if (inversionNumberCheck())
{
printf("unsolvable\n");
continue;
}
memset(open, , sizeof(open));
memset(close, , sizeof(close));
memset(pa, , sizeof(pa));
memset(f, , sizeof(f));
memset(dir, , sizeof(dir));
ans = A_star();
if (ans == -)
printf("unsolvable\n");
else
PrintPath(); while (find_min.empty())
find_min.pop();
}
return ;
}

HDOJ 1043 Eight(A* 搜索)的更多相关文章

  1. BFS(八数码) POJ 1077 || HDOJ 1043 Eight

    题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...

  2. hdu 1043(经典搜索)

    题意: 给你一个初始的图,然后每次输入一个图,要求移动x最小的步数达到和初始图一样,输出路径 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6 7 8 5 6 7 ...

  3. HDOJ(HDU).1016 Prime Ring Problem (DFS)

    HDOJ(HDU).1016 Prime Ring Problem (DFS) [从零开始DFS(3)] 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架 ...

  4. [dp]HDOJ4960 Another OCD Patient

    题意: 给一个n, 第二行给n堆的价值v[i], 第三行给a[i].  a[i]表示把i堆合在一起需要的花费. 求把n堆变成类似回文的 需要的最小花费. 思路: ①记忆化搜索 比较好理解... dp[ ...

  5. AC Again hdoj 1582 搜索

    AC Again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  6. HDU 1043 八数码(A*搜索)

    在学习八数码A*搜索问题的时候须要知道下面几个点: Hash:利用康托展开进行hash 康托展开主要就是依据一个序列求这个序列是第几大的序列. A*搜索:这里的启示函数就用两点之间的曼哈顿距离进行计算 ...

  7. 【HDOJ】1043 Eight

    这道题目最开始做的时候wa+TLE.后面知道需要状态压缩,最近A掉.并且练习一下各种搜索算法. 1. 逆向BFS+康拓展开. #include <iostream> #include &l ...

  8. HDOJ/HDU 2717 Catch That Cow 一维广度优先搜索 so easy..............

    看题:http://acm.hdu.edu.cn/showproblem.php?pid=2717 思路:相当于每次有三个方向,加1,减1,乘2,要注意边界条件,减1不能小于0,乘2不能超过最大值. ...

  9. (中等) HDU 1043 Eight,经典搜索问题。

    Problem Description The 15-puzzle has been around for over 100 years; even if you don't know it by t ...

随机推荐

  1. C#实现多态之一抽象

    1. 抽象类.抽象方法.抽象属性的特点 (1)      关键字:abstract (2)      抽象类只能是其他类的基类 (3)      抽象成员必须存在于抽象类中,但抽象类可以没有抽象成员, ...

  2. codeforces 603C. Lieges of Legendre sg函数

    题目链接 n堆石子, 可以拿走一堆中的一颗, 或者将一堆数量为2*x的石子分为k堆x个的石子.k由题目给出. k分奇偶讨论. k为偶数时,k堆x个的石子异或结果为0: k为奇数时, k堆x个石子异或结 ...

  3. [LeetCode]题解(python):139-Word Break

    题目来源: https://leetcode.com/problems/word-break/ 题意分析: 给定一个字符串s和一个字典dict,判断s是不是由字典dict里面的元素组成的. 题目思路: ...

  4. android-服务Service

    服务是在后台运行,负责更新内容提供器.发出意图.触发通知,它们是执行持续或定时处理的方式. 多线程一般捆绑服务执行任务,因为在activity中开辟多线程执行任务的话,子线程的生命周期得不到保障,可能 ...

  5. 【转】几个常用的Oracle存储过程

    http://blog.bossma.cn/database/some-oracle-storing-process/ 几个常用的Oracle存储过程 发布时间:2008年1月6日 / 分类:Data ...

  6. MySQL mysqlimport 从txt文件中导入数据到mysql数据库

    mysqlimport: 我说这个我们还是先从世界观方法论的高度来理解一下便有更加准确的把握.数据导入不外呼有两个部分 第一部分:目标对象--我们要把数据导给谁(mysqlimport 的目标对象自然 ...

  7. SQL Server ansi_null_default | ansi_null_dflt_on

    先说一下这两个变量是一个意思,只是它们的作用范围不同 alter database dbTest set ansi_null_default on;  -- 这个的作用域是整个SQL Server   ...

  8. 有感于NC的强大

    第一次知道nc(netcat)是好几年前的事了,那个时候天比现在更蓝,草比现在更绿,卤煮也还是一个刚上大学不久的青葱骚年... 现在把这个01年的老古董拿出来说好像有点炒冷饭的意思,资料也铺天盖地了说 ...

  9. BZOJ 4300 绝世好题(位运算)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4300 [题目大意] 给出一个序列a,求一个子序列b,使得&和不为0 [题解] ...

  10. ZOJ Monthly, March 2013

    A题 题目大意:给出一棵树,一开始节点值均为0,先要求完成在线操作:将某子树所有节点值取反,或者查询某子树总点权. 题解:很基础的线段树题,既然两个操作都是子树操作,那么就先树链剖分一下,将子树操作转 ...