AOJ 0121: Seven Puzzle (BFS DP STL 逆向推理)(转载)
转载自: http://m.blog.csdn.net/blog/Enjoying_Science/42008801
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=49880
题意:7数码问题。在2×4的棋盘上,摆有7个棋子,每个棋子上标有1至7的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格(用0表示),与空格相邻(上下左右)的棋子可以移到空格中,该棋子原先位置成为空格。给出一个初始状态(保证可以转移到最终状态),找出一种从初始状态转变成给定最终状态的移动棋子步数最少的移动步骤。
输入:多组输入,每组8个数,表示初始状态前四个数为第一行从左到右,后四个数为第二行从左到右。
输出:至少需要多少步可以从输入状态到达最终状态(0 1 2 3 4 5 6 7)
(图1)
(图2)
(图3)
分析:
乍一看这题没从入手,但只要采取逆向思维,还是可以用广度优先搜索解决。先不考虑如何用最小步数从输入状态到达最终状态,所有结果的最终状态都是(01234567),那么反过来想,只要求出最终状态到达所有结果时的最小步数并记录下来,接下来就是查表了。0表示空位置,对空位置周围的格子采用广度优先的方式移动到0,并记录下最小步数的结果即可。如上图所示,图1,可以选择让7移动过来变成图2,也可以选择让2移动过来变成图3。我们要做的只不过是不断重复这种选择,直至穷举所有情况并记录结果。
我主要是用一个map<string, int>来表示(01234567)到string 的最小步数int,只要当前结果还不存在,就加入map,必然能够穷尽状态。另外,在移动格子问题上,因为我采用string来表示当前状态,那么移动方向上下左右分别就是当前位置-4, +4, -1, +1。需要注意的是,位置3不能移动到位置4.
思路:与前几题的bfs不同,这次的bfs没有明确的移动对象,看似任意一个数都可以当成对象移动。这时我们只需要抓住一个格子就行,比如我们把0作为移动对象,那么0在地图中漫游所有的格子得到的肯定就是问题的解空间。由于题目的输入是多个case,如果对每个case都运行一遍bfs就会TLE。这时我们祭出dp技能,只需要一次bfs就将解空间算出来,以后每个case只要到解空间中去找就行了。
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <queue>
using namespace std; map<string, int> dp;
int direction[] = { , -, , - }; //************************************
// Method: bfs
// FullName: bfs
// Access: public
// Returns: void
// Qualifier: 让0漫游整个字串
//************************************
void bfs()
{
queue<string> que;
que.push("");
dp[""] = ;
while (!que.empty())
{
string now = que.front(); que.pop();
// p是'0'的位置
int p = ;
for (int j = ; j < ; ++j)
{
if (now[j] == '')
{
p = j;
break;
}
} for (int i = ; i < ; ++i)
{
int n = p + direction[i];
if ( <= n && n < &&
!(p == && i == ) && // 右上角不能再往右了
!(p == && i == )) // 左下角不能再往左了
{
string next = now;
swap(next[p], next[n]);
if (dp.find(next) == dp.end())
{
dp[next] = dp[now] + ;
que.push(next);
}
}
}
}
} ///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{ bfs();
string line;
while (getline(cin, line))
{
line.erase(remove(line.begin(), line.end(), ' '), line.end());
cout << dp[line] << endl;
} return ;
}
///////////////////////////End Sub//////////////////////////////////
#include <iostream>
#include <queue>
#include <map>
#include <string>
#include <algorithm> using namespace std; typedef pair<string, int> P; const int INF = ; //输入
string a; //移动方向
int op[] = {-, , -, }; map<string, int> dp; //保存从string变到"01234567"的int //计算从"01234567"转换到其他序列所需的最小步数
void bfs(){
//初始化
queue<P> que;
que.push(P("", ));
dp[""] = ;
//宽度优先搜索
while(!que.empty()){
P p = que.front();
que.pop();
string s = p.first;
int cur = p.second;
for(int i = ; i < ; i ++){
//构造下一次交换
int next = cur + op[i];
string str = s;
swap(str[cur], str[next]);
map<string, int>::iterator it = dp.find(str);
//判断是否可移动以及是否访问过
if( <= next && next <
&& !(cur == && next == ) && !(cur == && next == )
&& it == dp.end()){ que.push(P(str, next));
dp[str] = dp[s] + ;
}
}
}
} void solve(){
//删除空格
a.erase(remove(a.begin(), a.end(), ' '), a.end());
cout<<dp[a]<<endl;
} int main(int argc, char const *argv[]){
//先逆向构造所有情况,后直接读取输入用例的结果
bfs();
while(getline(cin, a)){
solve();
}
return ;
}
用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器
AOJ 0121: Seven Puzzle (BFS DP STL 逆向推理)(转载)的更多相关文章
- AOJ 0121: Seven Puzzle【BFS】
From: AOJ 0121 思路:与前几题的bfs不同,这次的bfs没有明确的移动对象,看似任意一个数都可以当成对象移动.这时我们只需要抓住一个格子就行,比如我们把0作为移动对象,那么0在地图中漫游 ...
- AOJ 0121 Seven Puzzle
7 パズル 7 パズルは 8 つの正方形のカードとこれらのカードがぴたりと収まる枠で構成されています.それぞれのカードには.互いに区別できるように 0, 1, 2, ..., 7 と番号がつけられてい ...
- Aizu/Aoj 0121 Seven Puzzle
这题应该算是经典的八数码问题的弱化版吧:给你一个4x2的方版,上面有0-7 八个数字,每次只能让编号0的方格跟他的上下左右的方格交换:所以也就是把方格0当做空格看待,每次只有空格周围的方格能够向空格处 ...
- AOJ 0121 Seven Puzzle {广度优先搜索}(*)
原题 题意 题意是有一个输入,比方: 1 0 2 3 4 5 6 7 摆成例如以下形状: 1 0 2 3 4 5 6 7 0表示空格.其它数字能够移动到0的位置.最后须要到例如以下形状: 0 1 2 ...
- ACM/ICPC 之 最短路-Floyd+SPFA(BFS)+DP(ZOJ1232)
这是一道非常好的题目,融合了很多知识点. ZOJ1232-Adventrue of Super Mario 这一题折磨我挺长时间的,不过最后做出来非常开心啊,哇咔咔咔 题意就不累述了,注释有写,难点在 ...
- ZOJ 3596Digit Number(BFS+DP)
一道比较不错的BFS+DP题目 题意很简单,就是问一个刚好包含m(m<=10)个不同数字的n的最小倍数. 很明显如果直接枚举每一位是什么这样的话显然复杂度是没有上限的,所以需要找到一个状态表示方 ...
- 【2019.8.14 慈溪模拟赛 T1】我不是!我没有!别瞎说啊!(notme)(BFS+DP)
\(IDA^*\) 说实话,这道题我一开始没想出正解,于是写了一个\(IDA^*\)... 但神奇的是,这个\(IDA^*\)居然连字符串长度分别为\(2500,4000\)的数据都跑得飞快,不过数据 ...
- UVALive 5066 Fire Drill --BFS+DP
题意:有一个三维的地图,有n个人被困住,现在消防队员只能从1楼的一个入口进入,营救被困者,每一个被困者有一个价值,当消防队员找到一个被困者之后,他可以营救或者见死不救,如果救的话,他必须马上将其背到入 ...
- poj 1651 Multiplication Puzzle (区间dp)
题目链接:http://poj.org/problem?id=1651 Description The multiplication puzzle is played with a row of ca ...
随机推荐
- Joomla 3.2.0 - 3.4.4 无限制SQL注入漏洞
http://www.sebug.net/vuldb/ssvid-89680#0-tsina-1-18081-397232819ff9a47a7b7e80a40613cfe1 http://10.21 ...
- 允许浏览器跨域访问web服务端的解决方案
今天和同事探讨了前后端如何真正实现隔离开发的问题,如果前端单独作为服务发布,势必会涉及到无法直接调用后端的接口的问题,因为浏览器是不允许跨域提交请求的. 所谓跨域访问,就是在浏览器窗口,和某个服务端通 ...
- ajaxfileupload.js
jQuery.extend({ createUploadIframe: function(id, uri) { //create frame var frameId = 'jUploadFrame' ...
- 使用Sublime Text 直接运行Quick-cocos2d-x 项目
一.新建一个编译系统 { "cmd": "D:/WorkSoftWare/Quick/quick-cocos2d-x-3.3rc0/quick/samples/Runni ...
- smarty入门
1 2 3 4 首先要有3个文件夹configs.templates.templates_c,在configs文件夹中有一个配置文件:test.conf,代码: title = Welcome t ...
- Eclipse安装jad插件进行反编译
1.下载的eclipse是免安装的工具: 打开eclipse后在windows-preference下没有找到jadClipse,希望显示这个插件: 方法一:Help-Eclipse Marketpl ...
- 大数相乘nyoj28
描述我们都知道如何计算一个数的阶乘,可是,如果这个数很大呢,我们该如何去计算它并输出它? 输入 输入一个整数m(0<m<=5000) 输出 输出m的阶乘,并在输出结束之后输入一个换行符 ...
- 如果使用 Excel5 ,输出的内容应该是GBK编码
下面就是php导出excel的程序 <?phpini_set("display_errors",1);//是否显示报错信息set_include_path(get_inclu ...
- ng-model和ng-bind区别
ng-bind has one-way data binding ($scope --> view). It has a shortcut {{ val }} which displays th ...
- DataGridView key points
Simple Examples => http://csharp.net-informations.com/datagridview/csharp-datagridview-readonly-c ...