poj2488 A Knight's Journey

http://poj.org/problem?id=2488

题目大意:骑士厌倦了一遍又一遍地看到同样的黑白方块,于是决定去旅行。

世界各地。当一个骑士移动时,他走的是“日”字。骑士的世界是他赖以生存的棋盘。我们的骑士生活在一个棋盘上,它的面积比普通的8 * 8板要小,但它仍然是矩形的。你能帮这个冒险的骑士制定旅行计划吗? 找到一条路,这样骑士每一次都能到每一个广场。骑士可以在棋盘的任何方格上开始和结束。输入从第一行的正整数n开始。下面的行包含n个测试用例。每个测试用例由一个带有两个正整数p和q的单行组成,其中1 <= p * q <= 26。这表示一个p * q棋盘,其中p描述了多少个不同的数1,…p存在,q描述存在多少个不同的字母。这些是拉丁字母表中的第一个q字母:A,…每个场景的输出从包含“Scenario #i:”的一行开始,其中i是从1开始的场景的数量。然后打印一行一行,其中包含了字母顺序的第一路径,它访问棋盘上的所有方块,然后是空行。通过将访问的方块的名称连接起来,可以在一行中给出路径。每个方名称由大写字母和数字组成。

如果不存在这样的路径,那么您应该在一行上输出impossible的内容。

也就是说横坐标时是字母(向右为正),纵坐标是数字(向下为正),骑士需要走完全图的方格,并找出包含了字母顺序的第一条路径,那么这就暗示了骑士的起点坐标一定是A1,只有是按字母排序第一个一定是A1。骑士走的是“日”字,那么根据字母排序骑士的横坐标和纵坐标减少或增加的遍历顺序是8个方向(-2,-1)(-2,1)(-1,-2)(-1,2)(1,-2)(1,2)(2,-1)(2,1),这样的遍历顺序,得到的第一条路径一定是按字母顺序的路径。

算法思想:回溯法,问题的解空间树是一颗八叉树,分别对应八个方向,设置相应的剪枝函数,1)如果出界,舍弃相应子树;2)如果找到了一条路径(一定是按字母排序的路径),用一个isSoluted记录,如果问题解决,则减去相应子树;3)我们可以用visited[ ][ ]记录该方格被访问,减去相应子树(重复走回路),并在回溯时设为未访问。

 1 #include <cstring>//使用memset()
 2 #include <iostream>
 3 using namespace std;
 4 //按字典排序的行走方向       8叉树
 5 const int dx[8] = { -2, -2, -1, -1, 1, 1, 2, 2 };
 6 const int dy[8] = { -1, 1, -2, 2, -2, 2, -1, 1 };
 7 const int N = 27;
 8 bool visited[N][N];//判断方格是否被访问
 9 struct step {//走路的记录
10     char x, y;
11 };
12 step path[N];//记录路径的
13 bool isSoluted;//能否走通
14 int cases, p, q;//记录案例数,p行123... q列ABC...
15 void Backtrade(int x, int y, int t)//x 和 y 为当前坐标 t为深度
16 {
17     path[t].x = x + 'A' - 1;   //转为 char 记录走的路径
18     path[t].y = y + '0';
19     if (t == p * q)//如果有一条路走完全部 则可解 直接退出回溯
20     {
21         isSoluted = true;
22         return;
23     }
24     for (int i = 0; i < 8; i++)
25     {
26         int nx = x + dx[i];
27         int ny = y + dy[i];
28         //剪枝函数 出界 或 已访问过 或 问题已解决 不进入相应子树
29         if (0 < nx && nx <= q && 0 < ny && ny <= p&& !visited[nx][ny] && !isSoluted)
30         {
31             visited[nx][ny] = true;
32             Backtrade(nx, ny, t + 1);
33             visited[nx][ny] = false;//回溯时撤回标记
34         }
35     }
36 }
37 int main()
38 {
39     cin>>cases;
40     for (int c = 1; c <= cases; c++)
41     {
42         isSoluted = false;
43         cin >> p >> q;
44         memset(visited, false, sizeof(visited));
45         visited[1][1] = true;    //从第一个字典序起点开始走
46         Backtrade(1, 1, 1);
47         cout<<"Scenario #"<<c<<":"<<endl;
48         if (isSoluted)
49         {
50             for (int i = 1; i <= p * q; i++)
51                 cout << path[i].x << path[i].y;
52             cout << endl;
53         }
54         else
55             cout<<"impossible"<<endl;
56         cout << endl;
57     }
58     return 0;
59 }

猜你喜欢

转载自www.cnblogs.com/DA799422035/p/8994075.html