题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043
因为状态不多,在样例不多的情况下,直接bfs也是能过的(POJ),但是对于样例多的HDU,需要把所有可能的结果都预处理一遍存起来,要的时候直接输出结果,就能快很多。
网上很多代码都有用康托展开做空间优化,不用康托展开优化,用一个map存结果,也是能过的,下面写了两个。
要注意的是,你bfs是反向扩展的,所以,方向和顺序都要反过来。
如果你存的结果也是char类型的,记的在后面补上 '\0'。
具体康托展开的原理可以参考我之前写的博客:https://blog.csdn.net/godleaf/article/details/86818162
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
using namespace std;
const int INF = 0x3f3f3f3f;
const int Maxn = 200+10;
struct Node {
char state[10], ans[100], cnt, pos;
};
char s[10] = "12345678x";
map<string, pair <string, bool> > vis;
int dir[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
char ch[5] = "lrud";
void bfs() {
vis.clear();
queue<Node> qu;
Node tmp;
for(int i = 0; i < 9; ++i) if(s[i] == 'x') {
tmp.pos = i; break;
}
tmp.cnt = -1; memcpy(tmp.state, s, sizeof(tmp.state));
vis[s].second = true; vis[s].first = "rl";
qu.push(tmp);
while (!qu.empty()) {
tmp = qu.front(); qu.pop();
int pi = tmp.pos/3, pj = tmp.pos%3, ii, jj;
Node now;
for(int i = 0; i < 4; ++i) {
ii = pi+dir[i][0], jj = pj+dir[i][1];
if(ii < 0 || ii > 2 || jj < 0 || jj > 2) continue;
now = tmp;
swap(now.state[ii*3+jj], now.state[now.pos]);
if(vis[now.state].second) continue;
vis[now.state].second = true;
now.pos = ii*3+jj;
now.ans[++now.cnt] = ch[i];
now.ans[now.cnt+1] = '\0';
vis[now.state].first = now.ans;
qu.push(now);
}
}
}
int main(void)
{
int cnt; char b[30];
bfs();
while (gets(b)){
cnt = 0;
memset (s, 0, sizeof(s));
for(int i = 0; i < strlen(b); ++i) if((b[i] >= '1' && b[i] <= '8') || b[i] == 'x') s[cnt++] = b[i];
if(vis[s].second) {
string tmp = vis[s].first;
for(int i = tmp.size()-1; i >= 0; --i) cout << tmp[i];
cout << endl;
}
else cout << "unsolvable" << endl;
}
return 0;
}
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int Maxn = 1e6+10;
char s[10] = "123456780";
char ans[Maxn][50];
int dir[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} }, n[15];
char op[5] = "lrud";
bool vis[Maxn];
int cantor(char* ss) {
int ret = 0;
for(int i = 0; i < 9; ++i) {
int cnt = 0;
for(int j = i+1; j < 9; ++j) {
if(ss[j] < ss[i]) cnt++;
}
ret += cnt*n[8-i];
}
return ret;
}
void decantor(int num, char *ss, int &pos) {
int p = 0; bool v[10];
memset(v, false, sizeof(v));
for(int i = 8; i >= 0; --i) {
int cnt = 0, tmp = num/n[i];
num %= n[i];
for(int j = 0; j < 9; ++j) {
if(v[j]) continue;
if(cnt == tmp) {
if(j == 0) pos = p;
ss[p++] = j+'0';
v[j] = true;
break;
}
cnt++;
}
}
ss[p] = '\0';
}
void bfs() {
queue<int> qu;
memset(vis, false, sizeof(vis));
int tmp = cantor(s);
qu.push(tmp);
vis[tmp] = true;
while(!qu.empty()) {
int num = qu.front(); qu.pop();
for(int i = 0; i < 4; ++i) {
char ch[10]; int pos, pi, pj;
decantor(num, ch, pos);
pi = pos/3; pj = pos%3;
pi += dir[i][0]; pj += dir[i][1];
if(pi < 0 || pi > 2 || pj < 0 || pj > 2) continue;
swap(ch[pi*3+pj], ch[pos]);
int now = cantor(ch);
if(vis[now]) continue;
vis[now] = true;
memcpy(ans[now], ans[num], sizeof(ans[now]));
int len = strlen(ans[now]);
ans[now][len] = op[i]; ans[now][len+1] = '\0';
qu.push(now);
}
}
}
int main(void)
{
int cnt; char b[30];
n[1] = n[0] = 1;
for(int i = 2; i <= 10; ++i) n[i] = n[i-1]*i;
bfs();
while (gets(b)){
cnt = 0;
memset (s, 0, sizeof(s));
for(int i = 0; i < strlen(b); ++i) {
if((b[i] >= '1' && b[i] <= '8')) s[cnt++] = b[i];
else if(b[i] == 'x') s[cnt++] = '0';
}
int tmp = cantor(s);
if(vis[tmp]) {
for(int i = strlen(ans[tmp])-1; i >= 0; --i) cout << ans[tmp][i];
cout << endl;
}
else cout << "unsolvable" << endl;
}
return 0;
}