类似题目:

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

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

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

面积计算_#define




编程计算由“*”号围成的下列图形的面积。面积计算方法是统计*号所围成的闭合曲线中水平线和垂直线交点的数目。如下图所示,在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:

把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:

把边界的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 }



后续:

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

面积计算_#ifdef_02面积计算_i++_03

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

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