hdu 1043(经典搜索)

时间:2023-03-08 20:58:14

题意:

给你一个初始的图,然后每次输入一个图,要求移动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->

好像有很多中方法解决这个问题:八数码的八个境界

①bfs + 康托展开+打表         /* 其他的还不会,有空去试试 - -

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
typedef long long ll;
using namespace std; const int MAXN=362900;//最多是9!/2
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
bool vis[MAXN];//标记
char path[MAXN][40];//记录路径
int cantor(int s[])//康拖展开求该序列的hash值
{
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++;
sum+=(num*fac[9-i-1]);
}
return sum+1;
} struct node
{
int matri[10];
int position;
char path[50];
int state;
}; queue<node>que;
char dire[5] = "dlur";
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; void bfs()
{
memset(vis,false,sizeof(vis));
node cur;
for(int i = 0; i < 8; i++)
cur.matri[i] = i+1;
cur.matri[8] = 0;
cur.state = 46234;
cur.path[0] = '\0';
cur.position = 8;
que.push(cur);
vis[cur.state] = true;
path[cur.state][0] = '\0';
while(!que.empty())
{
cur = que.front();
que.pop();
int x = cur.position/3;
int y = cur.position%3; for(int i = 0; i < 4; i++)
{
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx < 0 || tx > 2 || ty < 0 || ty > 2)
continue;
node t = cur; t.position =tx*3+ty;
t.matri[cur.position] = t.matri[t.position];
t.matri[t.position] = 0;
t.state =cantor(t.matri);
if(!vis[t.state])
{
path[t.state][0] = t.path[0] = dire[i];
int len = strlen(cur.path);
for(int j = 1;j <= len+1;j++)
path[t.state][j] = t.path[j] = cur.path[j-1];
vis[t.state] = true;
que.push(t);
}
}
}
} char ch;
int q[10];
int main()
{
bfs();
while(cin >> ch)
{
if(ch == 'x')
q[0] = 0;
else
q[0] = ch-'0';
for(int i = 1; i < 9; i++)
{
cin >> ch;
if(ch == 'x')
q[i] = 0;
else
q[i] = ch-'0';
}
int ans = cantor(q);
// printf("%d\n",ans);
if(!vis[ans])
printf("unsolvable\n");
else
{
cout <<path[ans]<<endl;
}
}
return 0;
} ②双向bfs + 康拓展开+奇偶剪枝 剪枝:当x左右移动时,序列不变;上下移动时,移动2位后逆序数+2,所以奇偶性不变 双向bfs:因为扩展越大,你要搜索的部分就更多.而同时从开头和结果开始理论上来说会快很多 #include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
typedef long long ll;
using namespace std; const int MAXN=370000;
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
int vis[MAXN];//标记
int vis2[MAXN];
int cantor(string s)//康拖展开求该序列的hash值
{
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++;
sum+=(num*fac[9-i-1]);
}
return sum+1;
} struct node
{
string path;
int state;
} From; struct node2
{
int num;
char ch;
} pre[MAXN]; char dire2[5] = "dlur";
char dire1[5] = "urdl";
int dir[4] = {-3,1,3,-1}; void pri(int t)
{
if(pre[t].num == -1)
return ;
pri(pre[t].num);
printf("%c",pre[t].ch);
} void bfs(node cur)
{
queue<node>que1;
queue<node>que2;
memset(vis,0,sizeof(vis));
memset(vis2,0,sizeof(vis2)); pre[0].num = pre[1].num = pre[2].num = -1;
node last,tp;
vis[cantor(cur.path)] = 1;
last.path ="123456780";
last.state = 8;
vis2[cantor(last.path)] = 2;
que1.push(From);
que2.push(last);
int num = 2; while(!que1.empty() && !que2.empty())
{
//正向搜索
cur = que1.front();
que1.pop();
int stat = cantor(cur.path);
if(vis2[stat])
{
pri(vis[stat]);
int k = vis2[stat];
while(pre[k].num != -1)
{
printf("%c",pre[k].ch);
k = pre[k].num;
}
printf("\n");
return;
}
for(int i = 0; i < 4; i++)
{
if(i==0&&cur.state<3)continue; //up
if(i==1&&cur.state%3 == 2)continue; //right
if(i==2&&cur.state>5)continue; //down
if(i==3&&cur.state%3 == 0)continue; //left
int posi = cur.state + dir[i];
tp = cur;
swap(tp.path[cur.state],tp.path[posi]);
int x = cantor(tp.path);
if(vis[x])
continue;
vis[x] = ++num; tp.state = posi;
pre[num].ch = dire1[i];
pre[num].num = vis[stat];
que1.push(tp);
} //反向搜索
last = que2.front();
que2.pop();
stat = cantor(last.path);
if(vis[stat])
{
pri(vis[stat]);
int k =vis2[stat];
while(pre[k].num!=-1)
{
printf("%c",pre[k].ch);
k=pre[k].num;
}
printf("\n");
return ;
}
for(int i = 0; i < 4; i++)
{
if(i==0&&last.state<3)continue;
if(i==1&&last.state%3==2)continue;
if(i==2&&last.state>5)continue;
if(i==3&&last.state%3==0)continue;
int posi = last.state + dir[i];
tp = last;
swap(tp.path[last.state],tp.path[posi]);
int x = cantor(tp.path);
if(vis2[x])
continue;
vis2[x] = ++num; tp.state = posi;
pre[num].ch = dire2[i];
pre[num].num = vis2[stat];
que2.push(tp);
}
}
printf("unsolvable\n");
} bool check(string a)
{
int num = 0;
for(int i = 0; i < 9; i++)
{
if(a[i] == '0' )
continue;
for(int j = i+1; j < 9; j++)
{
if(a[j] == '0') continue;
if(a[j] < a[i])
num++;
}
}
if(num & 1)
return true;
else
return false;
} char ch;
char a[100];
int p[10];
int main()
{
while(gets(a))
{
int tnum = 0;
int n=strlen(a);
From.path="";
for(int i=0; i<n; i++)
if(a[i]!=' ')
{
if(a[i]=='x')
{
From.state=tnum;
From.path+='0';
}
else
From.path+=a[i];
tnum++;
}
if(check(From.path))printf("unsolvable\n");
else
bfs(From);
}
return 0;
} ③A*算法+康拓展开+奇偶剪枝 它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。走到终点的代价为f[n],主要由已经花费的代价g[n]和将要花费的代价h[n]决定,f[n] = g[n] + h[n],由于要找最短的路径,优先判定f[n]较小的。 而在本题中g[n]即是已经走过的步数,h[n]则是当前情况移动到-> 123456780的最小步数. #include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
typedef long long ll;
using namespace std; const int MAXN=362880;
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880};
// 0!1!2!3! 4! 5! 6! 7! 8! 9!
int vis[MAXN];
int cantor(int s[])
{
int sum=0;
for(int i=0; i<9; i++)
{
int num=0;
for(int j=0; j<i; j++)
if(s[j]>s[i])num++;
sum+=(num*fac[i]);
}
return sum;
} struct node2
{
int pre;
char ch;
} pre[MAXN]; struct node
{
int matri[10];
int position;
int have,to;
int state;
bool operator < (const node a)const
{
return have+to>a.have+a.to;
}
}; char dire[5] = "urdl";
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; int fx[]={2,0,0,0,1,1,1,2,2},fy[]={2,0,1,2,0,1,2,0,1};
int get_(node a)
{
int ans = 0;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++){
if(a.matri[i*3+j]){
ans+=abs(i-fx[a.matri[i*3+j]])+abs(j-fy[a.matri[i*3+j]]);
}
}
return ans;
}
int fina[10]; void pri(int k)
{
if(pre[k].pre == -1) return;
pri(pre[k].pre);
printf("%c",pre[k].ch);
} void bfs(node cur)
{
priority_queue<node>que;
memset(vis,0,sizeof(vis));
vis[cur.state] = 1;
int tnum = 1;
pre[1].pre = -1;
for(int i = 0; i < 8; i++)
fina[i] = i+1;
fina[8] = 0;
int _ans = cantor(fina);
cur.have = 0;
que.push(cur);
while(!que.empty())
{
cur = que.top();
que.pop();
int x = cur.position/3;
int y = cur.position%3;
int num = cur.state;
if(num == _ans)
{
int k = vis[num];
pri(k);
printf("\n");
return ;
}
for(int i = 0; i < 4; i++)
{
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx < 0 || tx > 2 || ty < 0 || ty > 2)
continue;
node t = cur; t.position =tx*3+ty;
t.matri[cur.position] = t.matri[t.position];
t.matri[t.position] = 0;
t.have++;
t.to = get_(t);
t.state =cantor(t.matri);
if(!vis[t.state])
{
vis[t.state] = ++tnum;
pre[tnum].pre = vis[num];
pre[tnum].ch = dire[i];
que.push(t);
}
}
}
printf("unsolvable\n");
} bool check(int a[])
{
int num = 0;
for(int i = 0; i < 9; i++)
{
if(a[i] == 0 )
continue;
for(int j = i+1; j < 9; j++)
{
if(a[j] == 0) continue;
if(a[j] < a[i])
num++;
}
}
if(num & 1)
return true;
else
return false;
} char ch;
int main()
{
while(cin >> ch)
{
node from;
if(ch == 'x')
{
from.matri[0] = 0;
from.position = 0;
}
else
from.matri[0] = ch-'0';
for(int i = 1; i < 9; i++)
{
cin >> ch;
if(ch == 'x')
{
from.matri[i] = 0;
from.position = i;
}
else
from.matri[i] = ch-'0';
}
int ans = cantor(from.matri);
from.state = ans;
// printf("%d\n",ans);
if(check(from.matri))
printf("unsolvable\n");
else
bfs(from);
}
return 0;
}