POJ 1979 Red and Black (回溯)

Descirbe:
There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles.

Write a program to count the number of black tiles which he can reach by repeating the moves described above.
Input:
The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

'.' - a black tile
'#' - a red tile
'@' - a man on a black tile(appears exactly once in a data set)
The end of the input is indicated by a line consisting of two zeros.
Output:
For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).
Sample Input:
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0
Sample Output:
45
59
6
13

题目传送门:POJ 1979

题目大意:

(翻译有限,凑合着看)

有一个棋盘,上面有黑的,又红的,现在你站在一个黑块上,只能往前后左右四个位置走,并且不能踩红块,黑块只能走一次,问总共能走多少黑块

解题思路:

比较典型的回溯法,用二维字符数组存入棋盘,递归搜索,如果符合条件,就继续递归,否则回溯,每一次踩到黑块就ans+1.

AC代码:

 

 1 #include 
 2 #include 
 3 #include 
 4 using namespace std;
 5 char s[25][25]; // 二维数组存棋盘
 6 int f[25][25];  // 标志数组,存是否走过这里的信息
 7 int w,h,x,y;   // 列,行,起始位置x,y
 8 int ans;    // 走过的黑块数
 9 void Search(int m, int n)
10 {
11     f[m][n] = 1; // 标志这个地方已经走过
12     ans++;   // 块数加一,初始地方也是黑的,也要加一
13     // 只要没有出界,并且是黑块,也没有走过,就可以走,继续搜索
14     if(m+1 <= h && s[m+1][n] == '.' && f[m+1][n] == 0) Search(m+1,n);
15     if(m-1 >= 1 && s[m-1][n] == '.' && f[m-1][n] == 0) Search(m-1,n);
16     if(n+1 <= w && s[m][n+1] == '.' && f[m][n+1] == 0) Search(m,n+1);
17     if(n-1 >= 1 && s[m][n-1] == '.' && f[m][n-1] == 0) Search(m,n-1);
18 }
19 int main()
20 {
21     s[0][0] = 0; // 下标从1开始,0下标特殊处理一下
22     while(~scanf("%d%d",&w,&h) && w+h)
23     {
24         memset(f,0,sizeof(f)); // 初始全部为未走过
25         ans = 0;   // 注意,每个样例要先初始化答案
26         for(int i = 1; i <= h; i++)
27         {
28             for(int j = 1; j <= w; j++)
29             {
30                 //读入答案,因为总是读入换行之类的其他字符,所以用此方法
31                 // 感觉这样麻烦了,应该有更好办法
32                 scanf("%c",&s[i][j]);
33                 if(s[i][j] == '@' || s[i][j] == '.' || s[i][j] == '#') continue;
34                 else scanf("%c",&s[i][j]);
35                 // 如果在这里就找到初始位置'@',并记录下来的话,会出错,
36                 // 暂时不知道为什么,就重新扫面一边
37             }
38         }
39         // 扫描,找到起始位置,坑爹就坑爹到这了,解决了好长时间
40         for(int i = 1; i <= h; i++)
41         {
42             for(int j = 1; j <= w; j++)
43             {
44                 if(s[i][j] == '@')
45                 {
46                     x = i;
47                     y = j;
48                 }
49             }


50 } 51 //进入函数 52 Search(x,y); 53 printf("%d\n",ans); // 打印答案 54 } 55 return 0; 56 }

 

小结:

回溯算是搜索的一种方式吧,有个初始条件,或者初始状态,开始在一定范围,一定条件下搜索,如果满足条件了,就记录下来,否则,如果出界了,或者违规了,就回溯,继续搜索。

 

你可能感兴趣的:(POJ 1979 Red and Black (回溯))