UVa 11529
题目大意:见刘汝佳《算法竞赛入门经典——训练指南》P173
解题思路:
先求出对于每一个点,有多少个三角形包含它,把各个点得到的数值加起来的总和除以 C[n][3] 即可得出答案。对于每一个点,可以求出有多少个三角形不包含它,设为tmp,C[n-1][2] - tmp = 包含这个点的三角形数。那么现在的问题就是如何求出不包含这个点的三角形数:
我们先把指定的这个点作为原点将其他所有点进行极角排序,从0开始枚举排序后的每一个点,把原点到枚举的点的射线作为一个平角的一条边,那么所有在这个平角的一侧的点与枚举的点组成的三角形都不会经过原点。好吧,这部分好难讲,而且我又很菜很菜,只能在代码里面尽量作些注释。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 6 using namespace std; 7 typedef long long ll; 8 const int maxn=1200+3; 9 const double PI=acos(-1.0); 10 struct point{ 11 double x,y; 12 }inp[maxn]; 13 int n; 14 double r[maxn<<1]; 15 double s; 16 double counts(int d){ 17 int cnt=0; 18 for(int i=0;i<n;i++){ 19 if(i==d) continue; 20 double tp=atan2(inp[i].y-inp[d].y,inp[i].x-inp[d].x); 21 r[cnt]=tp; 22 r[cnt+n-1]=tp+2*PI; //这里对每一个角多做了一个投影,防止后面的点找不到180度以内的点 23 cnt++; 24 } 25 cnt=2*n-2; 26 sort(r,r+cnt); 27 double ans=0; 28 int mv=0; 29 for(int i=0;i<n-1;i++){ 30 double tmp=r[i]+PI; 31 while(tmp>r[mv]) mv++; //这个mv有效的防止了重复计算 32 double cnt=mv-i-1; 33 ans+=cnt*(cnt-1)/2; 34 } 35 return s-ans; 36 } 37 int main(){ 38 int kase=1; 39 while(scanf("%d",&n)==1&&n){ 40 for(int i=0;i<n;i++) scanf("%lf %lf",&inp[i].x,&inp[i].y); 41 s=(double)(n-1)*(n-2)*(n-3)/6.0; //C[n-1][3] 42 double ans=0.0; 43 double sum=(double)n*(n-1)*(n-2)/6.0; //C[n][3] 44 for(int i=0;i<n;i++) 45 ans+=counts(i); 46 printf("City %d: %.2lf\n",kase++,ans/sum); 47 } 48 return 0; 49 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”