实现DFS之“农田灌溉”

这也是一道利用了DFS的题目,先说下我的思路:用一个二维数组记录每个字母所代表的含义(管道方向),用另一个二维数组记录4个方向的变换坐标;随后利用经典的DFS递归遍历即可~(还要注意在方向的处理上前后要保持一致,否则很容易计算出错 :| )


农田灌溉(Farm Irrigation)   

题目描述: 

Benny有一大片农田需要灌溉。农田是一个长方形,被分割成许多小的正方形。每个正方形中都安装了水管。不同的正方形农田中可能安装了不同的水管。一共有11种水管,分别用字母A~K标明,如图1所示。 


Benny农田的地图是由描述每个正方形农田中水管类型的字母组成的矩阵。例如,如果农田的地图为: ADC FJK IHE 

则农田中水管分布如图2所示。 


某些正方形农田的中心有水源,因此水可以沿着水管从一个正方形农田流向另一个正方形农田。如果水可以流经某个正方形农田,则整个正方形农田可以全部灌溉到。 Benny想知道至少需要多少个水源,以保证整个农田都能被灌溉到? 例如,图2所示的农田至少需要3个水源,图中的圆点表示每个水源。  
输入描述:  
输入文件中包含多个测试数据。每个测试数据的第1行为两个整数M和N,表示农田中有M行,每行有N个正方形。接下来有M行,每行有N个字符。字符的取值为'A'~'K',表示对应正方形农田中水管的类型。当M或N取负值时,表示输入文件结束。如果M和N的值为正数,则其取值范围是1≤M, N≤50。  
输出描述:  
对输入文件中的每个测试数据所描述的农田,输出占一行,为求得的所需水源数目的最小值。  

样例输入:  

2 2

DK

HF

3 3

ADC

FJK

IHE

-1 -1

样例输出: 

2 3


闲话少叙,直接上代码+注释~

Code:

  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. #define MAXN 50  
  5. char map[MAXN][MAXN];   //地图  
  6. int M, N;               //M:农田行数,N:每行的正方形个数  
  7.   
  8. int dir[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };   //管道坐标变换的四个方向:对应的顺序上下左右。  
  9. int dirO[11][4] = {  
  10.     {-1, 0, -1, 0}, {-1, 0, 0, 1}, {0, 1, -1, 0},  
  11.     {0, 1, 0, 1}, {-1, 1, 0, 0}, {0, 0, -1, 1},  
  12.     {-1, 0, -1, 1}, {-1, 1, -1, 0}, {0, 1, -1, 1},  
  13.     {-1, 1, 0, 1}, {-1, 1, -1, 1}  
  14.     };      //每种农田块对应的4个管道方向(-1为左或上、1为右或下、0为没有)。  
  15.   
  16. void DFS(int x, int y)  
  17. {  
  18.     int xx, yy;  
  19.     char temp = map[x][y];      //暂存当前农田块的形状,便于后面的比较~  
  20.     map[x][y] = 'Y';            //覆盖原来农田为已遍历  
  21.     for(int i = 0; i < 4; i++)  
  22.     {  
  23.         //计算下一个方向的坐标。  
  24.         xx = x + dir[i][0];       
  25.         yy = y + dir[i][1];  
  26.         if(xx<0 || xx>=MAXN || yy<0 || yy>=MAXN) continue;      //越界,跳至下一个方向的判断  
  27.           
  28.         //方向所代表的值:上0、下1、左2、右3。  
  29.       
  30.         //如果向上走(0)或向左走(2),比如向左走则判断原坐标的“左”管道和下一个方向坐标的“右”管道,方向所代表的值+1  
  31.         if(i == 0 || i == 2)      
  32.         {//若相邻两块农田管道能“接上”,即管道方向对应的值之积为-1  
  33.             if(map[xx][yy]!='Y' && dirO[temp-'A'][i]*dirO[map[xx][yy]-'A'][i+1]==-1) DFS(xx, yy);  
  34.         }  
  35.         //否则为向下走(1)或向右走(3),比如向下走则判断原坐标的“下”管道和下一个方向坐标的“上”管道。对应方向所代表的值-1  
  36.         else if(map[xx][yy]!='Y' && dirO[temp-'A'][i]*dirO[map[xx][yy]-'A'][i-1]==-1) DFS(xx, yy);  
  37.     }  
  38. }  
  39. int main()  
  40. {  
  41.     int i, j;  
  42.     int count;  
  43.     while(scanf("%d%d", &M, &N))  
  44.     {  
  45.         count = 0;  
  46.         if(M < 0 || N < 0) break;  
  47.         for(i = 0; i < M; i++) scanf("%s", map[i]);          //以行为单位为map地图赋值  
  48.         //遍历地图、递归计数  
  49.         for(i = 0; i < M; i++)                     
  50.             for(j = 0; j < N; j++)  
  51.                 if(map[i][j] != 'Y') { DFS(i, j); count++; }  
  52.         printf("%d\n", count);  
  53.     }  
  54.     return 0;  
  55. }  

运行结果:


如有Bug,欢迎拍砖~  :)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值