题意:小明要买三座房子,这三个房子构成一个三角形,已知n个房子的坐标,任何三个房子都不在一条直线上,又已知有m个宝藏的坐标,问房子构成的三角形内有奇数个宝藏的三角形有多少个。数据范围:n(3~100),m(1~1000)
分析:
简单的计算几何。记住这题的做法。
三角形内的点的个数=上面的线段下面的点的个数 -- 下面两条线段下面的点的个数(或者下面一条线段减上面两条线段,看具体位置情况,所以直接取绝对值就好)
n个点有n(n-1)/2条线段,不超过1W,枚举每条线段,再枚举每个宝藏的坐标(10^3),判断这个宝藏是否在这个线段下面,方法是判断横坐标是否在左右两端点的横坐标内,再用一个向量叉乘<0 就行了。处理了每条线段下面有多少个点之后,再三重循环(O(n^3))枚举线段(即枚举三角形)用上面的公式得到三角形内的点然后判定是否为奇数就行了。
这里要先做的一个处理就是把房子的坐标按横坐标第一关键字,纵坐标第二关键字排序,因为这样方便枚举。
注意这题求得三角形内点的方法和线段的表示方法(用两端点来标示cnt[i][j])
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; int n,m; struct node{ long long x,y; }; node a[200],b[1005]; int cnt[200][200]; bool cmp(node a,node b) { if(a.x!=b.x) return a.x<b.x; else return a.y<b.y; } long long f(node a,node b,node c) { long long ans=(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); return ans; } int main() { int cas=1; while(scanf("%d%d",&n,&m)!=EOF){ memset(cnt,0,sizeof(cnt)); for(int i=0;i<n;i++) scanf("%lld%lld",&a[i].x,&a[i].y); for(int i=0;i<m;i++) scanf("%lld%lld",&b[i].x,&b[i].y); sort(a,a+n,cmp); for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ for(int k=0;k<m;k++){ if(b[k].x>a[i].x&&b[k].x<a[j].x){ if(f(a[i],a[j],b[k])<0) cnt[i][j]++; } } } } int ans=0; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ for(int k=j+1;k<n;k++){ int tmp=abs(cnt[i][k]-cnt[i][j]-cnt[j][k]); if(tmp%2==1) ans++; } } } printf("Case %d: %d\n",cas++,ans); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-14 08:01:15