题目来源:洛谷
难度:普及+/提高(绿题)
链接:link
【重要】请读者在阅读下面的文章前至少先了解此题的含义
1 题目分析
这道题是一道有关计算几何的题。
我们先来解释几个题目有关的概念:
- 笛卡尔平面:可以理解为平面直角坐标系
- 靠从最后一个顶点到第一个顶点画一条边来封闭:图形边界无相交处
1.1 做法一:计算占格数量
这道题中的关键信息为:它的边要么是垂直的,要么是水平的。
既然这个多边形全部在格子上,是不是就意味着对于这个多边形来说,只要它占有了一个格子,就说明它占有了这个格子的全部呢?所以我们可以只需要统计它占格的数量即可。
如图,我分别用两种颜色标出了两种走向的边。我们不妨分别尝试一遍整张图从上至下,从左至右的扫描方式。对于绿边来说,当我们扫到第一条绿边时,开始出现阴影格子,扫到第二条时,暂时不再出现阴影格子,第三条时继续出现,第四条时再次停止,如此反复,直到最右下角的格子被扫描上为止。此时计算扫到了多少格子,就可以了。
计算一波时空复杂度:
- 时间复杂度:需要扫描完从左上角至右下角的所有格子,也就是最差需要扫描全图,复杂度为O(1),但常数项较大,最大可达200²=40000,还是可以接受的。
- 空间复杂度:一个存图的数组,开到205*205(其他几乎可以忽略不计),绝对不超出
125.00MB的限制。
做法二:数学公式
其中 S 为面积,n 为内部格点数目,s 为多边形边界上的格点数。扫描方式和上面的类似,在此处不加以赘述。
有兴趣者可以研究:洛谷讨论帖
2 代码实现
#include<bits/stdc++.h>
using namespace std;
#define MAXN 105
#define MAXXY 405
bool is_wall[MAXXY][MAXXY]={false};
struct point{
int x,y;
}polygon[MAXN];//存储该多边形
bool cnt=false;
int ans;
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<MAXXY;i++){
for(int j=0;j<MAXXY;j++){
is_wall[i][j]=false;
}
}
for(int i=0;i<n;i++){
scanf("%d %d",&polygon[i].x,&polygon[i].y);
}
int change;
for(int i=0;i<n;i++){//核心标墙代码
if(polygon[i].y==polygon[(i+1)%n].y){
if(polygon[(i+1)%n].x>polygon[i].x){
change=1;
}else{
change=-1;
}
for(int j=polygon[i].x+(change-1)/2;j!=polygon[(i+1)%n].x+
(change-1)/2;j+=change){
is_wall[polygon[i].y+200][j+200]=true;
}
}
}
for(int i=-200;i<=200;i++){//核心累加代码
for(int j=-200;j<=200;j++){
if(is_wall[j+200][i+200]){
cnt=!cnt;
}
if(cnt){
ans++;
}
}
}
printf("%d\n",ans);//输出
return 0;
}
参考资料
洛谷讨论帖https://www.luogu.com.cn/discuss/396530洛谷题目-P1183 多边形的面积https://www.luogu.com.cn/problem/P1183