湖南第十一届大学生程序设计大赛:多边形的公共部分(多边形面积并)
2025: 多边形的公共部分
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 6 Solved: 3
[Submit][Status][Web Board]
Description
给定两个简单多边形, 你的任务是判断二者是否有面积非空的公共部分。如下图, (a)中的两个
矩形只有一条公共线段,没有公共面积。
(a) (b)
在本题中,简单多边形是指不自交(也不会接触自身)、不含重复顶点并且相邻边不共线的多
边形。
注意: 本题并不复杂,但有很多看上去正确的算法实际上暗藏缺陷,请仔细考虑各种情况。
Input
输入包含不超过 100 组数据。每组数据包含两行,每个多边形占一行。多边形的格式是:第一
个整数 n 表示顶点的个数 (3<=n<=100), 接下来是 n 对整数(x,y) (-1000<=x,y<=1000), 即多边
形的各个顶点, 按照逆时针顺序排列。
Output
对于每组数据, 如果有非空的公共部分, 输出"Yes", 否则输出"No"。
Sample Input
4 0 0 2 0 2 2 0 2
4 2 0 4 0 4 2 2 2
4 0 0 2 0 2 2 0 2
4 1 0 3 0 3 2 1 2
Sample Output
Case 1: No Case 2: Yes
去年感受了没模板的痛苦,有这个模板那这个题就是水题了...
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<algorithm> using namespace std; const int maxn = 300; const double eps = 1e-8; const double pi = acos(-1.0); int dcmp(double x) { if(x > eps) return 1; return x < -eps ? -1 : 0; } struct Point { double x, y; }; double cross(Point a,Point b,Point c) ///叉积 { return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y); } Point intersection(Point a,Point b,Point c,Point d) { Point p = a; double t =((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))/((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x)); p.x +=(b.x-a.x)*t; p.y +=(b.y-a.y)*t; return p; } double PolygonArea(Point p[], int n) { if(n < 3) return 0.0; double s = p[0].y * (p[n - 1].x - p[1].x); p[n] = p[0]; for(int i = 1; i < n; ++ i) s += p[i].y * (p[i - 1].x - p[i + 1].x); return fabs(s * 0.5); } double CPIA(Point a[], Point b[], int na, int nb)//ConvexPolygonIntersectArea { Point p[20], tmp[20]; int tn, sflag, eflag; a[na] = a[0], b[nb] = b[0]; memcpy(p,b,sizeof(Point)*(nb + 1)); for(int i = 0; i < na && nb > 2; i++) { sflag = dcmp(cross(a[i + 1], p[0],a[i])); for(int j = tn = 0; j < nb; j++, sflag = eflag) { if(sflag>=0) tmp[tn++] = p[j]; eflag = dcmp(cross(a[i + 1], p[j + 1],a[i])); if((sflag ^ eflag) == -2) tmp[tn++] = intersection(a[i], a[i + 1], p[j], p[j + 1]); ///求交点 } memcpy(p, tmp, sizeof(Point) * tn); nb = tn, p[nb] = p[0]; } if(nb < 3) return 0.0; return PolygonArea(p, nb); } double SPIA(Point a[], Point b[], int na, int nb)///此函数中的 res 为两多边形相并面积 { int i, j; Point t1[4], t2[4]; double res = 0, num1, num2; a[na] = t1[0] = a[0], b[nb] = t2[0] = b[0]; for(i = 2; i < na; i++) { t1[1] = a[i-1], t1[2] = a[i]; num1 = dcmp(cross(t1[1], t1[2],t1[0])); if(num1 < 0) swap(t1[1], t1[2]); for(j = 2; j < nb; j++) { t2[1] = b[j - 1], t2[2] = b[j]; num2 = dcmp(cross(t2[1], t2[2],t2[0])); if(num2 < 0) swap(t2[1], t2[2]); res += CPIA(t1, t2, 3, 3) * num1 * num2; } } return PolygonArea(a, na)+PolygonArea(b, nb) - res; } Point p1[maxn], p2[maxn]; int n1, n2; int main() { int t = 1; while(scanf("%d", &n1) != EOF) { for(int i = 0; i < n1; i++) scanf("%lf%lf", &p1[i].x, &p1[i].y); scanf("%d",&n2); for(int i = 0; i < n2; i++) scanf("%lf%lf", &p2[i].x, &p2[i].y); double Area = SPIA(p1, p2, n1, n2); double Area1 = PolygonArea(p1,n1)+PolygonArea(p2,n2); if(Area==Area1) printf("Case %d: No\n",t++); else printf("Case %d: Yes\n",t++); } return 0; }