面积计算

类似题目:

洛谷P1162 填涂颜料   https://www.luogu.org/problemnew/show/P1162

填涂颜料 题解https://www.cnblogs.com/huashanqingzhu/p/10744207.html

 注意:本文所讲题目原为教材里面的练习题,当时的测试数据较弱,无法检测出本文所讲算法的bug。

下面的讲解仅提供一个参考思路激发思维。

正确的思路应该是在矩形外围加一个圈,全部设为0.从这个圈去搜索访问围墙外的那些0.

 如下图所示:白色块是原数据的0,黄色块是原数据的围墙1。绿色块是我们为解决这道题,额外添加的一圈0.从左上角的绿色块出发做搜索,可以把围墙外的所有0都访问完。然后统计棋盘里面的0扫描、统计一下个数即可。

 

 

 

编程计算由“*”号围成的下列图形的面积。面积计算方法是统计*号所围成的闭合曲线中水平线和垂直线交点的数目。如下图所示,在10*10的二维数组中,有“*”围住了15个0,因此面积为15。
首先输入m和n表示二维数组的行和列数目,然后输入m*n的二维数组,其中的*用1表示。

0 0 0 0 0 0 0 0 0 0
0 0 0 0 * * * 0 0 0
0 0 0 0 * 0 0 * 0 0
0 0 0 0 0 * 0 0 * 0
0 0 * 0 0 0 * 0 * 0
0 * 0 * 0 * 0 0 * 0
0 * 0 0 * * 0 * * 0
0 0 * 0 0 0 0 * 0 0
0 0 0 * * * * * 0 0
0 0 0 0 0 0 0 0 0 0
【样例输入】area.in
10 10
0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 0
0 0 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 1 0
0 1 0 1 0 1 0 0 1 0
0 1 0 0 1 1 0 1 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0
【样例输出】area.out
15

算法思路1:
参考:http://blog.csdn.net/harlow_cheng/article/details/51889928?locationNum=9
把1看成围墙,我们是想进入围墙的人,但是怎么也进不了,于是我们就在围墙的周围乱走,把能不进围墙就走到的地方走个遍。然而她就是这么无懈可击,我也真是醉了。然后删掉围墙。剩下的就是被围住的东西了,看得到,但是永远得不到,因为它们被围起来了。从每个角落都进行一次广搜,找连通块,找到了置为false就可以了。

说这么多啰嗦的废话,其实是这么个意思:

从左上角开始一行一行地扫描二维数组,对遇到的每一个0都做一次BFS,搜过的点标记为1。但是要注意:对每一行扫描时,若是遇到了围墙,就立即停止对这一行的扫描,接着扫描下一行。这样一来就可以把“围墙左侧”连通的0都变为1。

然后:从右下角开始对二维数组的每一行从右向左进行扫描,遇到0则做BFS,搜过的点标记1。同样地,每一行扫描时遇到围墙则该行扫描结束,进入下一行的扫描。
这样一来可以使得“围墙右侧”连通的0变为1。

最后:经过上面两个环节以后,数组中剩余的0应该都是围墙内的0。所以,扫描一遍二维数组,统计0的个数就是答案。

这个算法可以解决曲线(围墙)比较简单的情况。但是足以满足题目要求。

代码如下:

  1 #include <iostream>
  2 #include<queue>
  3 #include<stdio.h>
  4 using namespace std;
  5 
  6 #define localTest 1
  7 
  8 #define maxM 103
  9 #define maxN 103
 10 
 11 int m,n,a[maxM][maxN]={0};
 12 int dx[4]={-1,0,1,0};//上右下左
 13 int dy[4]={0,1,0,-1};
 14 
 15 void BFS(int x,int y);
 16 
 17 int main()
 18 {
 19     int i,j,ans=0;
 20     freopen("area_data/area5.in","r",stdin);
 21     scanf("%d%d",&m,&n);
 22     #ifdef localTest
 23     printf("%d %d\n",m,n);//
 24     #endif // localTest
 25     for(i=0;i<m;i++)
 26     {
 27             for(j=0;j<n;j++)
 28             {
 29                 scanf("%d",&a[i][j]);
 30                 #ifdef localTest
 31                 printf("%d ",a[i][j]);//
 32                 #endif // localTest
 33             }
 34             #ifdef localTest
 35             printf("\n");//
 36             #endif // localTest
 37     }
 38 
 39     for(i=0;i<m;i++)
 40     {
 41         for(j=0;j<n;j++)
 42         {
 43             if(a[i][j]==1) break;
 44             if(a[i][j]==0)
 45             {
 46                 BFS(i,j);
 47             }
 48         }
 49     }
 50     for(i=m-1;i>=0;i--)
 51     {
 52         for(j=n-1;j>=0;j--)
 53         {
 54             if(a[i][j]==1) break;
 55             if(a[i][j]==0)
 56             {
 57                 BFS(i,j);
 58             }
 59         }
 60     }
 61 
 62     #ifdef localTest
 63     printf("--------------\n");//
 64     #endif // localTest
 65     for(i=0;i<m;i++)
 66     {
 67         for(j=0;j<n;j++)
 68         {
 69             if(a[i][j]==0)ans++;
 70             #ifdef localTest
 71             printf("%d ",a[i][j]);//
 72             #endif // localTest
 73         }
 74         #ifdef localTest
 75         printf("\n");
 76         #endif // localTest
 77     }
 78     printf("%d\n",ans);
 79     return 0;
 80 }
 81 void BFS(int x,int y)
 82 {
 83     queue<int> qx,qy;
 84     int xx,yy,i;
 85 
 86     qx.push(x);
 87     qy.push(y);
 88     a[x][y]=1;
 89     while(!qx.empty())
 90     {
 91         for(i=0;i<4;i++)
 92         {
 93             xx=qx.front()+dx[i];
 94             yy=qy.front()+dy[i];
 95             if(xx>=0&&xx<m&&yy>=0&&yy<n&&a[xx][yy]==0)
 96             {
 97                 a[xx][yy]=1;
 98                 qx.push(xx); qy.push(yy);
 99             }
100         }
101         qx.pop(); qy.pop();
102     }
103 }

算法思路2:
参考:http://blog.csdn.net/u011123263/article/details/17249283
把边界的0全部赋值为-1,然后进行两次遍历,从上往下,在从下往上;
在遍历时,若当前位置为0,如果上,下,左,右有一个是-1,则把当前的0更改为-1;
遍历完后,再统计0的个数,就是所求的结果。

这个算法思路与算法思路1其实差不多,但是实现起来比较简单。

代码:

  1 #include<iostream>
  2 #include<stdio.h>
  3 using namespace std;
  4 
  5 #define localTest 1
  6 
  7 #define maxM 103
  8 #define maxN 103
  9 
 10 int m,n,a[maxM][maxN]={0};
 11 int dx[4]={-1,0,1,0};//上右下左
 12 int dy[4]={0,1,0,-1};
 13 
 14 int main()
 15 {
 16     int i,j,ans=0;
 17     int k,xx,yy;
 18     freopen("area_data/area5.in","r",stdin);
 19     scanf("%d%d",&m,&n);
 20     #ifdef localTest
 21     printf("%d %d\n",m,n);
 22     #endif // localTest
 23     for(i=0;i<m;i++)
 24     {
 25             for(j=0;j<n;j++)
 26             {
 27                 scanf("%d",&a[i][j]);
 28                 #ifdef localTest
 29                 printf("%2d ",a[i][j]);
 30                 #endif // localTest
 31             }
 32             #ifdef localTest
 33             printf("\n");
 34             #endif // localTest
 35     }
 36 
 37     for(i=0;i<m;i++)//把第0列和最后一列的0变为-1
 38     {
 39         if(a[i][0]==0) a[i][0]=-1;
 40         if(a[i][n-1]==0) a[i][n-1]=-1;
 41     }
 42     for(j=0;j<n;j++)//把第0行和最后一行的0变为-1
 43     {
 44         if(a[0][j]==0) a[0][j]=-1;
 45         if(a[m-1][j]==0) a[m-1][j]=-1;
 46     }
 47 
 48     for(i=1;i<m-1;i++)
 49     {
 50         for(j=1;j<n-1;j++)
 51         {
 52             if(a[i][j]==0)
 53             {
 54                 for(k=0;k<4;k++)
 55                 {
 56                     xx=i+dx[k]; yy=j+dy[k];
 57                     if(xx>=0&&xx<m&&yy>=0&&yy<n&&a[xx][yy]==-1)
 58                     {
 59                         a[i][j]=-1;
 60                         break;
 61                     }
 62                 }
 63             }
 64         }
 65     }
 66 
 67     for(i=m-1;i>=0;i--)
 68     {
 69         for(j=n-1;j>=0;j--)
 70         {
 71             if(a[i][j]==0)
 72             {
 73                 for(k=0;k<4;k++)
 74                 {
 75                     xx=i+dx[k]; yy=j+dy[k];
 76                     if(xx>=0&&xx<m&&yy>=0&&yy<n&&a[xx][yy]==-1)
 77                     {
 78                         a[i][j]=-1;
 79                         break;
 80                     }
 81                 }
 82             }
 83         }
 84     }
 85 
 86     #ifdef localTest
 87     printf("\n--------------\n");
 88     #endif // localTest
 89     for(i=0;i<m;i++)
 90     {
 91         for(j=0;j<n;j++)
 92         {
 93             if(a[i][j]==0)ans++;
 94             #ifdef localTest
 95             printf("%2d ",a[i][j]);
 96             #endif // localTest
 97         }
 98         #ifdef localTest
 99         printf("\n");
100         #endif // localTest
101     }
102     printf("%d\n",ans);
103     return 0;
104 }

 

后续:

为何要从左上角、右下角做两次的扫描呢?这个主要是考虑到有一些特殊情况下的输入。不多说,看下面这两组输入:

   

左边这组特殊的输入,在代码一当中,假如没有从右下角扫描处理“”围墙右侧”的0,则统计结果会多出一些0。所以需要从右下角再做一次扫描。

右侧这一组特殊的输入,在代码二中,假如只做左上角开始的扫描,那么中间那几个0会因为在检测到它们的时候,周围没有-1而保持0的值。所以要从右下角再做一次扫描。

 

posted on 2017-07-24 17:19  华山青竹  阅读(1357)  评论(0编辑  收藏  举报

导航