ACM-水池数目问题

大家好,这是我的第一篇博文。

最近在做ACM练习,在讨论区发现有很多问题的解法多种多样,故萌生念头将自己已AC题目的解题思路整理发文。

发此博文不为求得最高效的解题代码,旨在分享自己的解题方法,与大家交流学习,共同探讨。

言归正传-----南阳ACM-27题  水池数目

水池数目

时间限制:3000 ms  |  内存限制:65535 KB
难度:4
描述
***校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图,这个地图上仅标识了此处是否是水池,现在,你的任务来了,请用计算机算出该地图中共有几个水池。
输入
第一行输入一个整数N,表示共有N组测试数据
每一组数据都是先输入该地图的行数m(0<m<100)与列数n(0<n<100),然后,输入接下来的m行每行输入n个数,表示此处有水还是没水(1表示此处是水池,0表示此处是地面)
输出
输出该地图中水池的个数。
要注意,每个水池的旁边(上下左右四个位置)如果还是水池的话的话,它们可以看做是同一个水池。
样例输入
2
3 4
1 0 0 0 
0 0 1 1
1 1 1 0
5 5
1 1 1 1 0
0 0 1 0 1
0 0 0 0 0
1 1 1 0 0
0 0 1 1 1
样例输出
     2
     3

我的思路

在《数字图像处理》中,这类问题可用“区域生长法”来解决,有兴趣的可以查阅相关文献;

根据题目描述,四邻域有1相连通,可认为是一个区域(水池)。

这里利用数据结构中的堆栈来解决。

⑴首先将矩阵第一个为1(且未被标记)的点作为起始点,压入栈,并对其标记已入栈,水池数目+1;

⑵栈顶元素出栈,检查出栈元素周围四邻域[1]有无1(并且该位置没有被压入过栈[2]),若有则将其压入栈,并对其标记已入栈

⑶返回(2),至栈底为空结束。

⑷返回(1),至循环矩阵结束。

[1]注意边界位置,四邻域不要导致数组下标越界。

[2]可建立一个临时标记场,标记入栈元素。

代码如下:

  1 #include <iostream>
  2 #include <string.h>
  3 using namespace std;
  4 
  5 typedef struct Point
  6 {
  7     int x;
  8     int y;
  9     int val;
 10 }Point;
 11 
 12 #define MAXSIZE 10000                //堆栈最大元素个数
 13 #define OUTRANGE 0x0                //数组下标越界
 14 //定义堆栈
 15 template<class T>  //模版类
 16 class CStack
 17 {
 18 public:
 19     CStack(int num);
 20     int Push(T elem);    //入栈
 21     int Pop(T& elem); //出栈
 22     int count();            //栈中元素个数
 23     ~CStack();
 24 private:
 25     int Maxnum;            //栈元素最大数目
 26     T *top;                    //栈顶指针
 27     T *base;                //栈底指针            
 28 };
 29 template <typename T>
 30 CStack<T>::CStack(int num)
 31 {
 32   if(num>MAXSIZE)
 33     //exit(0); //AC判题不允许
 34     ;   
 35     Maxnum = num;
 36     base = new T[Maxnum];
 37     top = base;
 38 }
 39 template <typename T>
 40 CStack<T>::~CStack()            //析构函数
 41 {
 42     top = NULL;
 43     delete []top;
 44     delete[]base;
 45     base = NULL;
 46 }
 47 template <typename T>
 48 int CStack<T>::Push(T elem)
 49 {
 50     if ((top-base)>=Maxnum)
 51     {
 52         return 0;
 53     }
 54      top++;
 55     *top = elem;
 56     return 1;
 57 }
 58 template<typename T>
 59 int CStack<T>::Pop(T& elem)
 60 {
 61     if (top==base)
 62     {
 63         return 0;
 64     }
 65     elem = *top;
 66     top--;
 67     return 1;
 68 }
 69 template<typename T>
 70 int CStack<T>::count()
 71 {
 72     return top - base;            //等于 取整 (指针间地址长度/每个元素占用地址长度)-->本程序中为 (int)(top地址-base地址/sizeof(Point))=元素个数
 73 }
 74 int main()
 75 {
 76     int i_ceshi, iLine, iSample;
 77 
 78     cin >> i_ceshi;
 79     while (i_ceshi--)
 80     {
 81         int icount = 0;//水池个数
 82         cin >> iLine >> iSample;
 83 
 84         //构造水池矩阵
 85         int **Matrix = new int*[iLine];
 86         for (int i = 0; i < iLine;i++)
 87         {
 88             Matrix[i] = new int[iSample];
 89         }
 90 
 91         for (int i = 0; i < iLine;i++)
 92         {
 93             for (int j = 0; j < iSample;j++)
 94             {
 95                 cin >> Matrix[i][j];
 96             }
 97         }
 98 
 99         //构造像素标记场
100         int *mark = new int[iLine*iSample];
101         memset(mark, 0, iLine*iSample*sizeof(int));  //置为0
102 
103         //运用堆栈,区域生长
104         CStack<Point> stack(iLine*iSample);
105         
106         for (int i = 0; i < iLine;i++)
107         {
108             for (int j = 0; j < iSample;j++)
109             {
110                 Point pxlpoint;                                    //当前像元
111                 pxlpoint.x = i;
112                 pxlpoint.y = j;
113                 pxlpoint.val= Matrix[i][j];
114                 int currentpx = i*iSample + j;
115                 int mktmp = mark[currentpx];                        //标记场像元
116                 if (pxlpoint.val && mktmp == 0) {
117                     stack.Push(pxlpoint);
118                     mark[currentpx] = 1;
119                     icount++;
120                 }
121 
122                 while (stack.count())
123                 {
124                     //pop
125                     Point _pstack;
126                     stack.Pop(_pstack);
127                     Point _pLeft, _pRight, _pUp, _pDown;
128 
129                     /*----------------可修改为if  else if语句------------------------------------------------------------*/
130                     _pLeft.x = _pstack.x;
131                     _pLeft.y = _pstack.y> 0 ? _pstack.y -1  : _pstack.y;
132 
133                     _pRight.x = _pstack.x;
134                     _pRight.y = _pstack.y< iSample - 1 ? _pstack.y+ 1 : _pstack.y;
135 
136                     _pUp.x = _pstack.x > 0 ? _pstack.x - 1 : _pstack.x;
137                     _pUp.y = _pstack.y;
138 
139                     _pDown.x = _pstack.x < iLine - 1 ? _pstack.x + 1 : _pstack.x;
140                     _pDown.y = _pstack.y;
141 
142                     _pLeft.val =_pstack.y > 0 ? Matrix[_pstack.x][_pstack.y - 1] : OUTRANGE;                    //上下左右四邻域
143                     _pRight.val = _pstack.y < iSample - 1 ? Matrix[_pstack.x][_pstack.y + 1] : OUTRANGE;
144                     _pUp.val = _pstack.x > 0 ? Matrix[_pstack.x - 1][_pstack.y] : OUTRANGE;
145                     _pDown.val =_pstack.x < iLine - 1 ? Matrix[_pstack.x + 1][_pstack.y] : OUTRANGE;
146                     /*---------------------------------------------------------------------------------------------------------*/
147                     //检查pop周围4邻域像元,若存在1且未标记,push,并标记
148 
149                     int MarkLeft = mark[_pLeft.x*iSample + _pLeft.y];
150                     int MarkRight = mark[_pRight.x*iSample + _pRight.y];
151                     int MarkUp = mark[_pUp.x*iSample + _pUp.y];
152                     int MarkDown = mark[_pDown.x*iSample + _pDown.y];
153 
154                     if (_pLeft.val&&!MarkLeft){
155                         stack.Push(_pLeft);
156                         mark[_pLeft.x*iSample +_pLeft.y] = 1;
157                     }
158                     if (_pUp.val&&!MarkUp){
159                         stack.Push(_pUp);
160                         mark[_pUp.x*iSample + _pUp.y ] = 1;
161                     }
162                     if (_pRight.val&&!MarkRight) {
163                         stack.Push(_pRight);
164                         mark[_pRight.x *iSample + _pRight.y] = 1;
165                     }
166                     if (_pDown.val&&!MarkDown) {
167                         stack.Push(_pDown);
168                         mark[_pDown.x*iSample + _pDown.y] = 1;
169                     }
170 
171                 }//while(stack.count())
172             }//for
173         }//for
174         cout << icount << endl;
175     }//while(ceshi--)
176     return 0;
177 }
原文地址:https://www.cnblogs.com/qsbl-317541583/p/5674070.html