题目链接:Eight
解题思路:原来不知道,这是有名的8数码问题,它还用和15数码来废话半天。看了眼过的人数,直接BFS肯定就T了,况且,状态总数是9!, 36W,我怎么都不会估算复杂度了,这不是很少的状态么怎么还会TLE。
后来有人说打表,就是从终点向其他状态扩展同时记录操作序列,然后全部存到map里面,我看也有人用康托展开就存下了,其实map更简单。
还有无解的情况,其实就是逆序数的问题,终止节点的逆序数是0,然后你用空白节点和左右两边交换的话逆序数是不变的,那就只有上下了
我们分析a b c *这种情况,另一种是相反的。a和*互换
大小顺序
a b c
+2 0 0
a c b
+2 0 0
b a c
-1 +1 0
b c a
-1 -1 0
c a b
-1 +1 0
c b a
-1 -1 0
我们看到逆序数只有+2,+0,-2所以,逆序数只能为偶数,这也就是题目上面为什么说交换之后就无解了,那是因为交换两个相邻的数的话,逆序数不是+1就是-1,会从偶数变到奇数,从奇数变到偶数。就成无解了。
这是我在线打表的程序,打表差不多要650+MS左右。
#include<cstdio>
#include<map>
#include<queue>
#include<string>
#include<iostream>
using namespace std;
struct node{
int s, idx;
string seq;
node(){}
node(int ss, int iidx, string sseq){
s = ss, seq = sseq, idx = iidx;
}
};
int pp[10] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
map<int, string> ans;
string put[4] = {"d","u","r","l"};
int dir[9][4] = {{-1,3,-1,1},{-1,4,0,2},{-1,5,1,-1},{0,6,-1,4},{1,7,3,5},{2,8,4,-1},{3,-1,-1,7},{4,-1,6,8},{5,-1,7,-1}};
int getA(int s, int idx){
return s / pp[idx] % 10;
}
int change(int s, int a, int b){
a = 8 - a;
b = 8 - b;
int tem = getA(s, a);
s -= tem * pp[a];
s += getA(s, b) * pp[a];
s -= getA(s, b) * pp[b];
s += tem * pp[b];
return s;
}
void bfs(){
int i, j, k;
queue<node> mq;
mq.push(node(123456789, 8, ""));
ans[123456789] = "YES";
while(!mq.empty()){
node s = mq.front();
//cout << s.s << " " << s.idx << " " << s.seq << endl;
mq.pop();
for(i = 0; i < 4; i++){
int ss = s.s;
int ii = s.idx;
string qq = s.seq;
qq += put[i];
int tem = dir[ii][i];
if(tem == -1) continue;
ss = change(ss, tem, ii);
if(ans[ss] == ""){
ans[ss] = qq;
mq.push(node(ss, tem, qq));
}
}
}
}
char ac[100];
int main(){
int i, j, k;
// freopen("1.out", "w", stdout);
//freopen("1.in", "r", stdin);
bfs();
/*for(map<int, string>::iterator it = ans.begin(); it != ans.end(); it++){
cout << it->first << " " << it->second << endl;
}*/
while(gets(ac)){
int s = 0, tot = 0;
for(i = 0; tot < 9; i++){
if(ac[i] >= '1' && ac[i] <= '8'){
s = s * 10 + ac[i] - '0';
tot++;
}
if(ac[i] == 'x'){
s = s * 10 + 9;
tot++;
}
}
if(ans[s] == "YES"){
puts("");
}
else if(ans[s] == ""){
puts("unsolvable");
}
else{
string tem = ans[s];
for(i = tem.length() - 1; i >= 0; i--){
printf("%c", tem[i]);
}
printf("\n");
}
}
return 0;
}
还有一种启发式搜索的方法,2000+MS内搞定。