HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)
bfs搜索加记录路径
HDOJ-1043
- 主要思路就是使用双向广度优先搜索,找最短路径。然后记录路径,找到结果是打印出来。
- 使用康拓序列来来实现状态的映射。
- 打印路径推荐使用vector最后需要使用algorithm里的reverse进行路径的翻转。
- 注意本题有多组输入,这里的输入需要注意一下。
- 如果题目没有要求最短路径,那么使用深搜的话也可以记录路径,这里也给出了代码。
- 这里的记录路径的方法可以学习。还有判断没有解决方案的解决,利用逆序数。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#include<vector>
#include<map>
using namespace std;
const int maxn=362880;
int state[maxn][9];//从1开始
struct node{
int x;
int y;
int state;//编码
string s;
};
int fact[9];//阶乘
bool vis[maxn];
bool visr[maxn];
map<int,char> ma;
map<int,char> mar;
void init(){
fact[0]=1;
for(int i=1;i<=8;i++){
fact[i]=fact[i-1]*i;
}
ma[0]='u';mar[0]='d';
ma[1]='l';mar[1]='r';
ma[2]='d';mar[2]='u';
ma[3]='r';mar[3]='l';
}
int computeCon(string s){
int code=0;
for(int i=0;i<9;i++){
int cnt=0;
for(int j=i+1;j<9;j++){
if(s[j]-'0'<s[i]-'0')
cnt++;
}
code+=fact[8-i]*cnt;
}
return code;
}
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
bool in(int x,int y){
return x>=0&&x<3&&y>=0&&y<3;
}
string path[maxn];//-----------------------这种记录路径的方法很好----------------------------------
void bfs(string s,string final){
memset(vis,0,sizeof(vis));
memset(visr,0,sizeof(visr));
queue<node> q;
queue<node> q1;
int sx,sy;
for(int i=0;i<9;i++){
if(state[1][i]==0){
sx=i/3;
sy=i%3;
break;
}
}
int con=computeCon(s);
vis[con]=true;
node sta=node{sx,sy,con,s};
q.push(sta);
int conr=computeCon(final);
visr[conr]=true;
q1.push(node{2,2,conr,final});
path[con]="";
path[conr]="";
while(!q.empty()){
node temp=q.front();
q.pop();
//cout<<temp.state<<endl;
// if(temp.s==final){
// //print(temp.state);
// cout<<path[temp.state]<<endl;
// return true;
// }
for(int i=0;i<4;i++){
int tx=temp.x+dir[i][0];
int ty=temp.y+dir[i][1];
int newz=tx*3+ty;
int oldz=temp.x*3+temp.y;
if(in(tx,ty)){
string ns=temp.s;
ns[newz]=temp.s[oldz];
ns[oldz]=temp.s[newz];
int nowcon=computeCon(ns);
char direction=ma[i];
if(visr[nowcon]){
reverse(path[nowcon].begin(),path[nowcon].end());
cout<<path[temp.state]<<ma[i]<<path[nowcon]<<endl;
return;
}
if(!vis[nowcon]){
vis[nowcon]=1;
node now;
now.x=tx,now.y=ty,now.s=ns,now.state=nowcon;
q.push(now);
path[nowcon]=path[temp.state];
path[nowcon]+=direction;
//path[nowcon]=now;
//cout<<now.s<<endl;
}
}
}
temp=q1.front();
q1.pop();
for(int i=0;i<4;i++){
int tx=temp.x+dir[i][0];
int ty=temp.y+dir[i][1];
int newz=tx*3+ty;
int oldz=temp.x*3+temp.y;
if(in(tx,ty)){
string ns=temp.s;
ns[newz]=temp.s[oldz];
ns[oldz]=temp.s[newz];
int nowcon=computeCon(ns);
char direction=mar[i];
if(vis[nowcon]){
reverse(path[temp.state].begin(),path[temp.state].end());
cout<<path[nowcon]<<mar[i]<<path[temp.state]<<endl;
return;
}
if(!visr[nowcon]){
visr[nowcon]=1;
node now;
now.x=tx,now.y=ty,now.s=ns,now.state=nowcon;
q1.push(now);
path[nowcon]=path[temp.state];
path[nowcon]+=direction;
//path[nowcon]=now;
//cout<<now.s<<endl;
}
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
init();
char c;
while(cin>>c){
string s="";
if(c=='x')
state[1][0]=0;
else state[1][0]=c-'0';
s+=(state[1][0]+'0');
for(int i=1;i<=8;i++){
cin>>c;
if(c=='x')
state[1][i]=0;
else state[1][i]=c-'0';
s+=(state[1][i]+'0');
}
//cout<<s<<endl;
string final="123456780";
int k=0;
for(int i=0;i<9;i++){
if(!state[1][i])
continue;
for(int j=i+1;j<9;j++){
if(state[1][j]<state[1][i]&&state[1][j]){
k++;
}
}
}
if(k&1){
cout<<"unsolvable"<<endl;
continue;
}
bfs(s,final);
}
return 0;
}
这里是未Ac超时了的代码,而且记录路径的方法没有上面好。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#include<vector>
#include<map>
using namespace std;
const int maxn=362880;
int state[maxn][9];//从1开始
struct node{
int x;
int y;
int state;//编码
int father;
char direction;
string s;
};
int fact[9];//阶乘
bool vis[maxn];
map<int,char> ma;
map<string,int> conma;
void init(){
fact[0]=1;
for(int i=1;i<=8;i++){
fact[i]=fact[i-1]*i;
}
ma[0]='u';
ma[1]='l';
ma[2]='d';
ma[3]='r';
}
int computeCon(string s){
int code=0;
for(int i=0;i<9;i++){
int cnt=0;
for(int j=i+1;j<9;j++){
if(s[j]-'0'<s[i]-'0')
cnt++;
}
code+=fact[8-i]*cnt;
}
return code;
}
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
bool in(int x,int y){
return x>=0&&x<3&&y>=0&&y<3;
}
node path[maxn];
void print(int state){
vector<char> v;
//cout<<state<<endl;
while(path[state].direction!='n'){
//cout<<state<<endl;
v.push_back(path[state].direction);
state=path[state].father;
}
reverse(v.begin(),v.end());
for(int i=0;i<v.size();i++){
cout<<v[i];
}
cout<<endl;
}
bool bfs(string s,string final){
memset(vis,0,sizeof(vis));
queue<node> q;
int sx,sy;
for(int i=0;i<9;i++){
if(state[1][i]==0){
sx=i/3;
sy=i%3;
break;
}
}
int con=computeCon(s);
vis[con]=true;
node sta=node{sx,sy,con,-1,'n',s};
q.push(sta);
path[con]=sta;
while(!q.empty()){
node temp=q.front();
q.pop();
//cout<<temp.state<<endl;
if(temp.s==final){
print(temp.state);
return true;
}
for(int i=0;i<4;i++){
int tx=temp.x+dir[i][0];
int ty=temp.y+dir[i][1];
int newz=tx*3+ty;
int oldz=temp.x*3+temp.y;
if(in(tx,ty)){
string ns=temp.s;
ns[newz]=temp.s[oldz];
ns[oldz]=temp.s[newz];
int nowcon=computeCon(ns);
if(!vis[nowcon]){
vis[nowcon]=1;
node now;
char direction=ma[i];
now.x=tx,now.y=ty,now.father=temp.state,now.direction=direction,now.s=ns,now.state=nowcon;
q.push(now);
path[nowcon]=now;
//cout<<now.s<<endl;
}
}
}
}
return false;
}
int main(){
init();
char c;
while(cin>>c){
string s="";
if(c=='x')
state[1][0]=0;
else state[1][0]=c-'0';
s+=(state[1][0]+'0');
for(int i=1;i<=8;i++){
cin>>c;
if(c=='x')
state[1][i]=0;
else state[1][i]=c-'0';
s+=(state[1][i]+'0');
}
//cout<<s<<endl;
string final="123456780";
if(!bfs(s,final)){
cout<<"unsolvable"<<endl;
}
}
return 0;
}
HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)的更多相关文章
- hdu 1043 Eight (八数码问题)【BFS】+【康拓展开】
<题目链接> 题目大意:给出一个3×3的矩阵(包含1-8数字和一个字母x),经过一些移动格子上的数后得到连续的1-8,最后一格是x,要求最小移动步数. 解题分析:本题用BFS来寻找路径,为 ...
- 八数码问题 双向BFS/Hsh链表存储
转自洛谷 作者EndSaH #include<iostream> #include<string> #include<cmath> #include<cstr ...
- cdoj 414 八数码 (双向bfs+康拓展开,A*)
一道关乎人生完整的问题. DBFS的优越:避免了结点膨胀太多. 假设一个状态结点可以扩展m个子结点,为了简单起见,假设每个结点的扩展都是相互独立的. 分析:起始状态结点数为1,每加深一层,结点数An ...
- HDU 1043 Eight 八数码问题 A*算法(经典问题)
HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...
- Hdu 1043 Eight (八数码问题)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目描述: 3*3的格子,填有1到8,8个数字,还有一个x,x可以上下左右移动,问最终能否移动 ...
- HUD 1043 Eight 八数码问题 A*算法 1667 The Rotation Game IDA*算法
先是这周是搜索的题,网站:http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=6041 主要内容是BFS,A*,IDA*,还有一道K短路的,.. ...
- Eight (HDU - 1043|POJ - 1077)(A* | 双向bfs+康拓展开)
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...
- hdu1043 经典的八数码问题 逆向bfs打表 + 逆序数
题意: 题意就是八数码,给了一个3 * 3 的矩阵,上面有八个数字,有一个位置是空的,每次空的位置可以和他相邻的数字换位置,给你一些起始状态 ,给了一个最终状态,让你输出怎么变换才能达到目的. 思路: ...
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
随机推荐
- Codeforces Round #648 (Div. 2) C. Rotation Matching
题目链接:https://codeforces.com/contest/1365/problem/C 题意 有两个大小为 $n$ 的排列,可以循环左移或右移任意次,问最多有多少对同一值在同一位置. 题 ...
- hdu2430Beans(单调队列)
Mr. Pote's shop sells beans now. He has N bags of beans in his warehouse, and he has numbered them ...
- Codeforces Round #646 (Div. 2) E. Tree Shuffling dfs
题意: 给你n个节点,这n个节点构成了一颗以1为树根的树.每一个节点有一个初始值bi,从任意节点 i 的子树中选择任意k个节点,并按他的意愿随机排列这些节点中的数字,从而产生k⋅ai 的成本.对于一个 ...
- java——final、权限修饰符
final修饰类: final修饰成员方法: final修饰局部变量的时候: 对于基本类型来说,变量的数值不能改变 对于引用类型来说,变量的地址不能改变 final修饰成员变量的情况: 权限修饰符:
- POJ2785 4 Values whose Sum is 0 (二分)
题意:给你四组长度为\(n\)序列,从每个序列中选一个数出来,使得四个数字之和等于\(0\),问由多少种组成情况(仅于元素的所在位置有关). 题解:\(n\)最大可以取4000,直接暴力肯定是不行的, ...
- 2017, X Samara Regional Intercollegiate Programming Contest M. Last Man Standing (贪心,双指针)
题意:有\(n\)个吃鸡玩家,在某个时间段给你他们每个人的杀敌数,判断数据是否合法,并输出每个人对应的杀敌情况. 题解:刚开始写的是直接暴力枚举,向后去找并且标记,然后存到vector最后输出,结果一 ...
- 手摸手带你学移动端WEB开发
HTML常用标签总结 手摸手带你学CSS HTML5与CSS3知识点总结 手摸手带你学移动端WEB开发 好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Ro ...
- USB2.0协议学习笔记---USB数据包结构
USB包类型和传输过程 USB是一种串行总线,因此数据都是一位一位传输的,如同串口那样,但是USB在真实物理电路上却不是TTL电平,而是一种差分信号采用NRZI编码,就是用变化表示0,不变表示1,同 ...
- 翻译:《实用的Python编程》01_04_Strings
目录 | 上一节 (1.3 数字) | 下一节 (1.5 列表) 1.4 字符串 本节介绍处理文本的方法. 表示字面量文本 在程序中字符串字面量使用引号来书写. # 单引号(Single quote) ...
- 你所不知道的 cnblogs
你所不知道的 cnblogs cnblogs 学院 cnblogs 班级 refs https://academy.cnblogs.com/ https://academy.cnblogs.com/b ...