• 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 }
  • 相关阅读:
    插入排序
    python -- 给电视剧重命名
    程序员你为什么迷茫?
    如何把自己打造成技术圈的 papi 酱
    GitHub中国区前100名到底是什么样的人?
    Python+opencv 图像拼接
    VS2015 新Web项目(C#6)出现CS1617错误的解决
    .Net Task<T>的一种比较神奇的卡死情况(Wait/Result卡死, await能得到结果)
    Xamarin Android自学和实践步骤
    跨过几个坑,终于完成了我的第一个Xamarin Android App!
  • 原文地址:https://www.cnblogs.com/qsbl-317541583/p/5674070.html
Copyright © 2020-2023  润新知