HDU - 1043
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 x
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->
2 3 4 1 5 x 7 6 8Sample Output
ullddrurdllurdruldr
题意很简单,给你一个状态让你变成给定状态12345678X,输出路径,如果不行输出unsolvable
网上博客上有很多种做法,什么数码八大境界之类的,大家自己搜去,这里就只写了最简单也最容易理解的一种方法,bfs逆向打表+康拓展开,因为目标状态只有一种,而从目标状态可以变到的状态也是有限种,我们可以从目标状态为起点,进行bfs保存下从目标状态到达每一种状态的路径,这里的状态就是那个数组的不同顺序,因为直接存数组肯定超内存,而这是一个序列的不同排列,因此可以将状态通过康拓展开进行压缩hash一下,这样状态就只用一个数表示就可以了,因为是逆向的存储,所以只需要让方向数组和对应的方向字符数组恰好相反即可使得最终路径是正向的,这里用到了康托展开和康拓逆展开了解一下。
code:
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 362880;
int fac[] = {1,1,2,6,24,120,720,5040,40320,362880};
int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
char Indexx[5] = "durl";//与上面的方向是相反的,因为是逆向搜索的
int num[9];
int t[9];//临时存每个康拓展开值对应的排列
int Hash[maxn];//是否有这种状态
string path[maxn];
struct node{
int pos;//x在一维中的位置
int val;//康拓展开值
string path;//移动路径
};
int Cantor(int *s){
int sum = 0;
for(int i = 0; i < 9; i++){
int num = 0;
for(int j = i+1; j < 9; j++){
if(s[j] < s[i])
num++;//确定当前元素i在未出现的元素中是第几个(从小到大)
}
sum += fac[8-i] * num;
}
return sum;
}
void CantorReverse(int val,int *s){
//val--;
int vis[10] = {0};
for(int i = 0; i < 9; i++){
int tmp = val / fac[8-i];
for(int j = 0; j <= tmp; j++){
if(vis[j]) tmp++;
}
t[i] = tmp + 1;
vis[tmp] = 1;
val %= fac[8-i];
}
return;
}
void Bfs(){
memset(Hash,0,sizeof(Hash));
node st,ed;
for(int i = 0; i < 8; i++){
t[i] = i+1;
}
t[8] = 9;
st.pos = 8;
st.val = Cantor(t);
st.path = "";
queue q;
path[st.val] = "";
q.push(st);
while(!q.empty()){
st = q.front();
q.pop();
int x = st.pos / 3;
int y = st.pos % 3;
for(int i = 0; i < 4; i++){
int xx = x + dir[i][0];
int yy = y + dir[i][1];
if(xx >= 0 && xx < 3 && yy >= 0 && yy < 3){
ed = st;
ed.pos = xx * 3 + yy;
CantorReverse(st.val,t);
swap(t[ed.pos],t[st.pos]);//交换
ed.val = Cantor(t);
if(!Hash[ed.val]){
Hash[ed.val] = 1;
ed.path = Indexx[i] + ed.path;//从上一路径基础上移动
q.push(ed);
path[ed.val] = ed.path;
}
}
}
}
}
int main(){
char str[110];
Bfs();
while(gets(str)){
int len = strlen(str);
int cnt = 0;
for(int i = 0; i < len; i++){
if(str[i] >= '0' && str[i] <= '9')
num[cnt++] = str[i] - '0';
else if(str[i] == 'x')
num[cnt++] = 9;
}
if(Hash[Cantor(num)])
cout << path[Cantor(num)] << endl;
else cout << "unsolvable" << endl;
}
return 0;
}
今天学习了一下A*算法
下面有一篇博客写的非常清楚简单明白A*算法
这道题A*算法可以以较快速度求出答案路径,但是根据估值函数的不同却不一定能保证最优,但是能保证最快
下面是这道题A*算法的写法
code:
#include
#include
#include
#include
#include
#include
#include
#include