POJ 2243 简单搜索 (DFS BFS A*)

时间:2023-02-10 14:44:34

题目大意:国际象棋给你一个起点和一个终点,按骑士的走法,从起点到终点的最少移动多少次。

求最少明显用bfs,下面给出三种搜索算法程序:

 1 // BFS
2 #include<cstdio>
3 #include<queue>
4 #include<cstring>
5 using namespace std;
6 const int maxn=10;
7 int r1,c1,r2,c2;
8 struct Node
9 {
10 int r,c;
11 Node(int r,int c):r(r),c(c){}
12 };
13 int vis[maxn][maxn];
14 int dist[maxn][maxn];
15 queue<Node> Q;
16 int dr[]={-2,-2,-1,-1,1,1,2,2};
17 int dc[]={-1,1,2,-2,2,-2,1,-1};
18 int BFS()
19 {
20 if(r1==r2&&c1==c2) return 0;
21 while(!Q.empty()) Q.pop();
22 memset(vis,0,sizeof(vis));
23 vis[r1][c1]=1;
24 dist[r1][c1]=0;
25 Q.push(Node(r1,c1));
26 while(!Q.empty())
27 {
28 Node node=Q.front();Q.pop();
29 int r=node.r,c=node.c;
30 for(int d=0;d<8;d++)
31 {
32 int nr=r+dr[d];
33 int nc=c+dc[d];
34 if(nr>=0&&nr<8 && nc>=0 &&nc<8 &&vis[nr][nc]==0)
35 {
36 if(nr==r2&&nc==c2) return dist[r][c]+1;
37 dist[nr][nc]=1+dist[r][c];
38 Q.push(Node(nr,nc));
39 vis[nr][nc]=1;
40 }
41 }
42 }
43 return -1;
44 }
45 int main()
46 {
47 char str1[10],str2[10];
48 while(scanf("%s%s",str1,str2)==2)
49 {
50 r1=str1[1]-'1';
51 c1=str1[0]-'a';
52 r2=str2[1]-'1';
53 c2=str2[0]-'a';
54 printf("To get from %s to %s takes %d knight moves.\n",str1,str2,BFS());
55 }
56 return 0;
57 }

DFS:

注意visited结点,如果步数较小也继续搜索

 1 // DFS
2 #include<cstdio>
3 #include<algorithm>
4 #include<cstring>
5 using namespace std;
6 const int maxn=10;
7 int r1,c1,r2,c2;
8 struct Node
9 {
10 int r,c;
11 Node(int r,int c):r(r),c(c){}
12 };
13 int vis[maxn][maxn];
14 int dist[maxn][maxn];
15 int dr[]={-2,-2,-1,-1,1,1,2,2};
16 int dc[]={-1,1,2,-2,2,-2,1,-1};
17 int ans;//最终答案
18 void DFS(int r,int c,int len)
19 {
20 if(ans<=len || r<0 || r>=8 || c<0 || c>=8) return ;//剪枝
21 if(r==r2&&c==c2) ans=min(ans,len);
22 if(vis[r][c]==0 || dist[r][c]>len)
23 {
24 vis[r][c]=1;
25 dist[r][c]=len;
26 }
27 else if(vis[r][c]==1 && len >= dist[r][c] )
28 return ;
29 for(int d=0;d<8;d++)
30 {
31 int nr=r+dr[d];
32 int nc=c+dc[d];
33 DFS(nr,nc,len+1);
34 }
35 }
36 int main()
37 {
38 char str1[10],str2[10];
39 while(scanf("%s%s",str1,str2)==2)
40 {
41 r1=str1[1]-'1';
42 c1=str1[0]-'a';
43 r2=str2[1]-'1';
44 c2=str2[0]-'a';
45 memset(vis,0,sizeof(vis));
46 ans=10;
47 DFS(r1,c1,0);
48 printf("To get from %s to %s takes %d knight moves.\n",str1,str2,ans);
49 }
50 return 0;
51 }

A*算法:

g函数为沿路径从起点到当前点的移动耗费(经过的步数),启发函数h为当前格子到终点横坐标差与纵坐标差的和(曼哈顿距离),用优先队列保存每个状态按照g+h排序。通常,我们令水平或者垂直移动的耗费为10,对角线方向耗费为14。取这些值是因为沿对角线的距离是沿水平或垂直移动耗费的的根号2,或者约1.414倍。为了简化,可以用10和14近似。

bfs

 1 #include <cstring>
2 #include <iostream>
3 #include <cmath>
4 #include <algorithm>
5 #include <vector>
6 #include <queue>
7 #include <cstdio>
8
9 using namespace std;
10
11 const int maxn = 10;
12
13 struct Node{
14 int x,y,step;
15 int f,g,h;
16 // g函数为走到当前状态的经过的步数,启发函数h为当前格子到终点横坐标差与纵坐标差的和,用优先队列保存每个状态按照g+h排序
17 bool operator < (const Node & tmp) const{
18 return f > tmp.f;
19 }
20 }node;
21
22 bool visd[maxn][maxn];
23 priority_queue<Node> Que;
24 int dirs[8][2]={{-2,-1},{-2,1},{2,-1},{2,1},{-1,-2},{-1,2},{1,-2},{1,2}};
25 int start_x,start_y,end_x,end_y,ans;
26
27 bool isIN(int x,int y)
28 {
29 if(x>=8||x<0)return false;
30 if(y>=8||y<0)return false;
31 return true;
32 }
33 void init()
34 {
35 memset(visd,false,sizeof(visd));
36 while(!Que.empty())Que.pop();
37 Node S;
38 S.x=start_x;S.y=start_y;
39 S.step=0;S.g=0;S.h=(abs(end_x-start_x)+abs(end_y-start_y))*10;
40 S.f=S.g+S.h;
41 visd[S.x][S.y]=true;
42 Que.push(S);
43 ans=-1;
44 }
45
46 void Astar()
47 {
48 Node A,B;
49 while(!Que.empty())
50 {
51 A=Que.top();Que.pop();
52 if(A.x==end_x&&A.y==end_y)
53 {
54 ans=A.step;
55 break;
56 }
57 for(int i=0;i<8;i++)
58 {
59 int xx=dirs[i][0]+A.x;
60 int yy=dirs[i][1]+A.y;
61 if(isIN(xx,yy)==false||visd[xx][yy])continue;
62 B.x=xx;B.y=yy;
63 B.step=A.step+1;
64 B.g=A.g+23;
65 B.h=(abs(end_y-yy)+abs(end_x-xx))*10;
66 B.f=B.g+B.h;
67 visd[B.x][B.y]=true;
68 Que.push(B);
69 }
70 }
71 }
72
73 int main()
74 {
75 char line[10];
76 while(gets(line))
77 {
78 start_x=line[0]-'a';start_y=line[1]-'1';
79 end_x=line[3]-'a';end_y=line[4]-'1';
80 init();
81 Astar();
82 printf("To get from %c%c to %c%c takes %d knight moves.\n",line[0],line[1],line[3],line[4],ans);
83 }
84
85 return 0;
86 }