Eight
Time Limit: 10000 msMemory Limit: 32768 KB
Scenario
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
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 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
这道题A的不容易呀!!!(看咱这内存耗得)
题后两句话:
①啊啊啊啊啊这题真的不容易啊,思路就很难想,不容易A掉...
②这题本人犯迷糊了...(其实是没理解清楚)
上面两幅图,左边是本人用自己代码输入测试样例跑出来的,然后右边是系统给的output。
乍一看好像挺对,但仔细观察后发现最后几个操作符两两相反,于是我就懵*了嘤嘤嘤嘤...
然后反复推敲,自己debug,搞各种测试发现好像完美无瑕...(其实是真的哈哈哈哈哈哈)
然后不甘心的情况下我就...选择场外求助了
(特别鸣谢我的老师,讲课好,还耐心的帮助了我~)
对!!!这个题的移动过程是不唯一的,我最后用我的运行结果手动模拟了一下,确定结果是一致的,然后提交上去就A掉了。
真是个心酸的故事...希望下次可以长点心hhhhhh
③回归正题,这题其实就是最强大脑里的数字迷盘游戏,我代码思路的核心是深度优先搜索空格的移动位置来生成状态空间转换图,然后直接判新的Input是否可以搜到,搜到就反向把路径输出来;找不到就直接say goodbye。(注意深度优先的时候反向来搜索,从goal开始更好写算法,也更好理解)
④好的,接下来把图模型整理上来就交作业辽~继续加油吧!!!
这道题真的耗了我很大的心血,代码奉上,请多指教~
#include<iostream>
#include<string>
#include<map>
#include<iterator>
#include<queue>
using namespace std;
map<string,string> mark; //把状态转换图记录下来,前后转换关系形成mark映射
map<string,string>::iterator it;
string goal="12345678x";
queue<string> qstr; //广搜队列
void push_to_mark(string str1,string str2,int t1,int t2){ //映射函数
str2=str1;
str1[t2]='x';
str1[t1]=str2[t2]; //建立新的状态字符串str1
it=mark.find(str1);
if(it==mark.end()){ //如果mark中没有str1状态,则将其加入mark
mark[str1]=str2; //str1是由str2转换来的
qstr.push(str1); //将当前搜索到的状态放入队列
}
}
void Search(){
//初始化
string s1=goal,s2;
qstr.push(s1);
mark[s1]=s1; //方便最后的判断,直接判映射值和goal是否相同即可
int t1,t2;
while(!qstr.empty()){
s1=qstr.front(); qstr.pop();//取出待搜索状态
for(t1=0;t1<9;t1++) if(s1[t1]=='x') break; //查到x位置立即弹出
if(t1/3!=0) { t2=t1-3; push_to_mark(s1,s2,t1,t2); } //由于不是最上面的一列,所以可以上移一格
if(t1/3!=2) { t2=t1+3; push_to_mark(s1,s2,t1,t2); } //由于不是最下面的一列,所以可以下移一格
if(t1%3!=0) { t2=t1-1; push_to_mark(s1,s2,t1,t2); } //由于不是最左边的一列,所以可以左移一格
if(t1%3!=2) { t2=t1+1; push_to_mark(s1,s2,t1,t2); } //由于不是最右边的一列,所以可以右移一格
}
}
int main(){
//初始化
int ans1,ans2;
string str,markstr;
char ch;
mark.clear();
Search(); //记录状态转换图
while(cin>>ch){
str="";str+=ch;
for(int i=1;i<9;i++) { cin>>ch; str+=ch;}
it=mark.find(str);
if(it==mark.end()) cout<<"unsolvable"<<endl; //mark中找不到str则输出unsolvable
else{
while(str!=goal){
it=mark.find(str);
markstr=it->second;
for(ans1=0;ans1<9;ans1++) if(str[ans1]=='x') break;
for(ans2=0;ans2<9;ans2++) if(markstr[ans2]=='x') break;
int ans=ans2-ans1;
if(ans==-3) cout<<"u";
else if(ans==3) cout<<"d";
else if(ans==1) cout<<"r";
else if(ans==-1) cout<<"l";
str=markstr;
}
cout<<endl;
}
}
return 0;
}