hdu 4353
来源:互联网 发布:电子打鼓软件下载 编辑:程序博客网 时间:2024/05/17 22:15
先简单说说这道题的题意吧,题目讲的大概是个挖金矿的故事,首先分别给出n个普通点(这些点是你可以自己选择的用来圈金矿的点),以及m个金矿所在点。你所需要计算的,就是从n中任意选择x个点(3<=x<=n)组成一个x边形,然后用这个x边形除以x边形内所圈住的金矿的个数,我们暂且将这个比值称之为“性价比”。
好了,题目的要求是输出最高的性价比,那么怎么得到这个性价比呢?首先3000MS的时间虽然足够你暴力的了,但并不意味着真的足够随便暴力枚举,尤其是n的最大取值是200。200个点所能组成的多边形数目是很可怕的。那么,就需要我们仔细分析下题意了....
我们分析下对于一个边数大于三的多边形,它的“性价比”是如何得到的呢?
(每个三角形的面积和)/(每个三角形围住的点的个数和)==(每个三角形的“性价比”之和)/三角形总个数。
也就是说,多边形的性价比来自于每个三角形的性价比的平均值,既然是平均值,那么在所有的三角形中,自然会有比大于平均值、等于平均值和小于平均值的”性价比“存在,那么回头再看看题目要的输出是什么?没错,就是最大的”性价比“,所以最终的结果必然是某个三角形的”性价比“。
也许有人看到这儿会问样例2的问题了。不得不说,值得一提的是这道题的Hint,真的是很误导你不往正确的思路上想。Hint中所取的看似是内个凹四边形“性价比”最高,但其实,它只是恰好等于由(0,0),(0,5),(2,2)或者(0,0),(5,0),(2,2)所组成的三角形的“性价比罢了,而Hint中确有偏偏只给你由(0,0),(0,5),(5,0)组成的“性价比”三角形。用心险恶啊~~~
知道了以上内容,这道题唯一的问题就只剩下求每个三角形内金矿个数这一问题了。因为3000MS,所以对于三层for循环O(n^3)遍历所有三角形的个数时间是足够我们“计算几何瞎暴力”的了,但是如果再添一层for循环去遍历m个金矿点在不在该三角形内,时间复杂度就成了可怕的O(n^3*m),超时是必然的了。于是便需要采取一些手段,我的办法是利用叉积来计算对于任意一条有向边AB,计算出它所在直线的右侧的金矿点的个数。并记录在二维数组对应位置record[A][B]中,时间复杂度同样是三次幂的O(n^2*m),但在查询的时候是O(1)的复杂度,查询的方法也很容易理解。
例如:
三角形内部的点的个数=向量AB右侧的点-向量BC右侧的点-向量CA右侧的点。
由此,这道题以总时间复杂度O(n^2*m+n^3)而结束。
#include<cstdio>#include<iostream>#include<algorithm>#include<cmath>#define MIN(a,b) ((a<b)?(a):(b))const double inf = 1e9;const double eps = 1e-6;using namespace std;int n,m;int num[210][510];struct point{ double x,y; bool operator < (const point &a) const{ return x<a.x; }}pointn[210],pointm[510];double multi(point p0,point p1,point p2){ return fabs((double)((p1.x - p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y))*0.5);}//计算面积,其实只用一个叉积就够了,但是三角形习惯用这个了int det(point A,point B,point C){ return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);}void In(point a,point b,int &cnt){ int x1=a.x; int x2=b.x; for(int i=0;i<m;i++) if(x1<=pointm[i].x&&pointm[i].x<x2) if(det(a,b,pointm[i])>0) cnt++;}int main(){ int t; scanf("%d",&t); for(int count=1;count<=t;count++){ double ans=-1; scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%lf%lf",&pointn[i].x,&pointn[i].y); sort(pointn,pointn+n); for(int i=0;i<m;i++) scanf("%lf%lf",&pointm[i].x,&pointm[i].y); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) In(pointn[i],pointn[j],num[i][j]=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 cnt=num[i][k]-num[i][j]-num[j][k]; if(cnt==0) continue; double area=multi(pointn[i],pointn[j],pointn[k]); double tmp=fabs(area/cnt); if(ans==-1||tmp<ans) ans=tmp; } } } if(ans==-1) printf("Case #%d: -1\n",count); else printf("Case #%d: %lf\n",count,ans); } return 0;}
- hdu 4353
- hdu 4353 计算几何
- HDU 4353 - Finding Mine
- HDU 4353 枚举
- HDU 4353 Finding Mine
- hdu
- hdu
- HDU
- hdu ()
- hdu
- hdu
- HDU
- HDU
- hdu
- hdu
- HDU
- Hdu
- hdu
- Android问题集锦之四十五:undefined reference to 'srand'
- 导弹拦截<DP><贪心><C++>
- 记录——《C Primer Plus (第五版)》第十章编程练习第二题
- TCP/IP详解 卷1 笔记 第13章 IGMP: internet组管理协议
- hdu 1175 连连看问题
- hdu 4353
- 楼道声光控工作原理
- POJ 1050 To the Max
- 关于jquery 如何判断checkbox 是否选中
- 【剑指offer】-从尾到头打印链表
- LeetCode Delete Node in a Linked List 链表
- 记项目中的一次错误之RecyclerView
- 记录——《C Primer Plus (第五版)》第十章编程练习第三题
- bzoj1621【Usaco2008 Open】Roads Around The Farm