zoukankan      html  css  js  c++  java
  • 面积计算

    类似题目:

    洛谷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
    ",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("
    ");//
     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("--------------
    ");//
     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("
    ");
     76         #endif // localTest
     77     }
     78     printf("%d
    ",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
    ",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("
    ");
     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("
    --------------
    ");
     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("
    ");
    100         #endif // localTest
    101     }
    102     printf("%d
    ",ans);
    103     return 0;
    104 }

    后续:

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

       

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

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

  • 相关阅读:
    .NET写的Email可以群发邮件的实用函数
    動網中用到的幾個Function和一個JS[base64encode,base64decode,md5,sendmail,js]
    HTML在线编辑器
    IIS虚拟目录控制类
    实用正则表达式(实用篇)
    IIS站点管理类
    精巧sql语句
    圖片滾動代碼
    c# 添加图片水印,可以指定水印位置+生成缩略图
    JavaScript旋转图片
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/7230022.html
Copyright © 2011-2022 走看看