题目大意:
Fling是一款手机益智游戏。
这个游戏在7*8的棋盘上玩。每一局游戏的棋盘上包含许多毛球。为了获得游戏胜利,你需要从棋盘上移除毛球直到只剩下一个毛球在棋盘上。你把一个毛球扔向另外一个毛球,通过撞击使得另外一个毛球飞出棋盘,用这种方式来完成移除毛球。你可以把毛球向上、下、左、右四个方向扔出去。被扔出去的毛球一旦撞到另一个毛球,就会在另一个毛球前面的格子停下来。同时被撞击的毛球将按照之前的方向向前滚动,直到最后一个被撞击的毛球飞出边界。举个栗子,位于(0, 0)坐标的毛球向右滚动,撞击到位于(0, 5)坐标的毛球,这时撞击的毛球将在(0 ,4)坐标停下来。此外,被撞击的毛球将向右朝前滚动。你不能将一个毛球扔向四个方向中任何一个与它相邻的毛球。然而,一个滚动的毛球在运动的方向撞击与他相邻的毛球这是允许的。
输入:
输入包含许多组测试用例。
每一组测试用例 是 7行,每行8个字符来描述的棋盘。‘X’代表一个空格子,‘O’代表一个有毛球的格子。任何一个棋盘中,毛球的数量不会超过12个。每组测试用例之间包含一个空行。
输出:
对于每组测试用例,打印一行格式为“CASE #NUM:”的字符串,NUM的地方为当前测试用例的数量。
接下来,打印每次扔毛球的记录。每一行包含两个整数X,Y和一个字符Z。(X, Y)表示被选中扔出去的毛球的坐标,最左上角的格子是(0, 0)。Z代表毛球移动的方向:U(上)、L(左)、R(右)、D(下);
在两个例子之间输出一个空格。
你可以认为每局都有解。
如果有许多胜利方案,输出最小的一个。两个序列 A (A1, A2, A3 ... An)和B (B1, B2, B3 ... Bn),假设k是最小的一个使得Ak != Bk成立的数。
定义:A < B
(1) Ak中的X < Bk中的X
(2) 在Ak中的X = Bk中的X的条件下,Ak中的Y < Bk中的Y
(3) 在Ak中的(X, Y) = Bk中的(X, Y)的条件下,Ak中的Z < Bk中的Z
Z的大小按照这个序列:U < L < R < D。
这题目需要注意的地方:当一个毛球移动后,会导致其他毛球在棋盘上的位置变化,因此下一次搜索的位置不能从上一次搜索提供的位置开始,不然的话得打的结果就不一定满足题目要求(the smallest one)。如果要得到题目要求的答案,每次搜索都需要扫描棋盘,按照扫描到毛球的先后顺序来进行本次搜索,这样得到的结果才可以满足题目要求。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <deque> 5 #include <stack> 6 using namespace std; 7 8 typedef struct Node //记录结果的结点结构 9 { 10 int row; //行 11 int col; //列 12 int d; //方向 13 Node() {} 14 Node(int _row, int _col, int _dir) :row(_row), col(_col), d(_dir){} 15 }Node; 16 17 const int dir[4][2] = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } }; //方向:上,左,右,下 18 char board[10][10]; //棋盘 19 deque<Node> deq; //记录移动方向 20 21 /* 判断是否越界的函数 */ 22 inline bool inBoard(int row, int col) 23 { 24 return 0 <= row && row < 7 && 0 <= col && col < 8; 25 } 26 27 /* dfs搜索 */ 28 bool dfs(int furball) //furball为剩余毛球的数量 29 { 30 if (1 == furball) //当剩余毛球的数量为1的时候,表示游戏胜利 31 return true; 32 33 /* 由于毛球的碰撞会改变棋盘其他毛球的位置, 34 如果按照前一个dfs函数提供的开始点来搜索, 35 往往不能得到题目要求的结果,因此每次都要 36 扫描一遍棋盘,找到“最小的点”来搜索 */ 37 for (int i = 0; i < 7; ++i)//行 38 { 39 for (int j = 0; j < 8; ++j)//列 40 { 41 if (‘O‘ == board[i][j]) 42 { 43 for (int k = 0; k < 4; ++k) //方向 44 { 45 int row = i + dir[k][0];//向前走一步 46 int col = j + dir[k][1]; 47 48 if (false == inBoard(row, col)) continue; 49 if (‘O‘ == board[row][col]) continue; //第一步必须是空位置,不然不能向这个方向走 50 51 stack<int> recode_row; //recode_row和recode_col用来记录毛球搜索前的的位置,方便后面的回溯 52 stack<int> recode_col; 53 54 55 56 //从出发点出发,导致的一系列变化 57 while (inBoard(row, col) && ‘X‘ == board[row][col]) //如果是‘X‘就一直走,直到走出边界或者碰到毛球才停下来 58 { 59 row += dir[k][0]; 60 col += dir[k][1]; 61 } 62 63 //遇到furball,处理撞击过程(若走出界了还没碰到毛球,说明这个方向不能走) 64 if (true == inBoard(row, col) && ‘O‘ == board[row][col]) 65 { 66 //记录本次dfs的出发点 67 deq.push_back(Node(i, j, k)); 68 69 //用栈来保存毛球的信息,用于回溯 70 recode_row.push(i); 71 recode_col.push(j); 72 73 //记录好了毛球信息后,就可以在棋盘上修改毛球了, 74 board[i][j] = ‘X‘; 75 board[row - dir[k][0]][col - dir[k][1]] = ‘O‘; 76 77 //扔第一个毛球引发的其他毛球移动 78 //例如:处理这种情况“XOXOXOOX”,(1,1)向R方向移动,导致其他毛球移动 79 while (1) 80 { 81 recode_row.push(row); 82 recode_col.push(col); 83 board[row][col] = ‘X‘; 84 row += dir[k][0]; 85 col += dir[k][1]; 86 while (inBoard(row, col) && ‘X‘ == board[row][col]) 87 { 88 row += dir[k][0]; 89 col += dir[k][1]; 90 } 91 if (true == inBoard(row, col) && ‘O‘ == board[row][col]) 92 board[row - dir[k][0]][col - dir[k][1]] = ‘O‘; 93 else 94 break; 95 } 96 97 if (dfs(furball - 1)) return true; 98 99 //回溯 100 int r, c; 101 while ( 1 != recode_row.size()) 102 { 103 r = recode_row.top(); 104 c = recode_col.top(); 105 board[r][c] = ‘O‘; 106 board[r - dir[k][0]][c - dir[k][1]] = ‘X‘; 107 recode_row.pop(); 108 recode_col.pop(); 109 } 110 r = recode_row.top();//与起点相邻的点不需要改成‘X‘ 111 c = recode_col.top(); 112 board[r][c] = ‘O‘; 113 deq.pop_back(); 114 } 115 } 116 } 117 } 118 } 119 return false; 120 } 121 122 int main(void) 123 { 124 int CASE = 1; 125 int furball = 0; 126 while (scanf("%s", board[0]) != EOF) 127 { 128 furball = 0; 129 for (int i = 1; i < 7; ++i) 130 scanf("%s", board[i]); 131 for (int i = 0; i < 7; ++i) 132 for (int j = 0; j < 8; ++j) 133 if (‘O‘ == board[i][j]) 134 furball++;//记录毛球的总数 135 136 //搜索 137 dfs(furball); 138 139 //输出 140 Node res; 141 if (CASE > 1) 142 printf("\n"); 143 printf("CASE #%d:\n",CASE++); 144 while (!deq.empty()) 145 { 146 res = deq.front(); 147 printf("%d %d ", res.row, res.col); 148 switch (res.d) 149 { 150 case 0: 151 printf("U\n"); 152 break; 153 case 1: 154 printf("L\n"); 155 break; 156 case 2: 157 printf("R\n"); 158 break; 159 case 3: 160 printf("D\n"); 161 break; 162 } 163 deq.pop_front(); 164 } 165 } 166 return 0; 167 }