Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=1922
【前言】
xlj问我有没有题做,没有的话给我一道。
我说我正在做,等一下。
然后敲完了一道离散的题,然后接过了这道题。
想了段时间之后找到了做法。
发现xlj的想法也是一样。
于是开始敲。谁知道这才是悲剧的开始。
敲好后debug过了sample,交之后狂WA。
hdu1922这道题只有几个人过了这道题,解题报告也找不到。
然后各种能考虑的情况都考虑进去,还是WA。
最后找到了解题报告,发现原来是poj3004。
做法也是一样的思路。
但还是WA。
前前后后在HDU上交了二十多次,在poj上交了几次。
xlj回来后继续,但是sample还没过。
后来发现他里面错漏百出。然后就改啊改。
但我的还是WA。
找到一份代码对照之后还是WA。
回宿舍后又提交了十几二十次,还是WA。
终于,在临近十二点的时候,发现了错误。
第一处错误是少写了一个字母,后来发现的时候,
虽然改过来了,但是下面又改错了。
于是华丽丽地傻×了。
如果没有那处错误的话,应该早就过了。
所以,这道题虽然出的很好,是神题,但并不是真的神了,而是我傻了……
【思路】
首先,如果某个点可以覆盖到原点,则把那个点直接去掉。
对于每个点,找出它的极角范围。从原点引该点半径为d的圆的两条切线,然后计算出切线的两个极角。
每个点都有两个极角,变成了贪心的区间覆盖问题。
要求自定义的区间个数,使所有的已知区间都包含这些区间,要使区间个数最小。
由于是圆环,所以扫描每个点,以该点作为断点,然后贪心一遍,取它们的最小值。
【代码】
#include <iostream> #include <algorithm> #include <cmath> using namespace std; #define min(a,b) ((a)<=(b)?(a):(b)) const int maxn = 1000; const double pi = acos(-1.0); struct point { double x, y; double l, r; }pt[maxn*2+1]; bool cmp(const point &a, const point &b) { return a.l<b.l; } void set(point &p, double d, double dis) { double a, b; if (p.x==0) { if (p.y>0) a = 0.5*pi; else a = 1.5*pi; } else if (p.y==0) { if (p.x>0) a = 0; else a = pi; } else { a = asin(fabs(p.y*1.0)/dis); if (p.x<0 && p.y>=0) a = pi - a; else if (p.x<=0 && p.y<0) a += pi; else if (p.x>0 && p.y<=0) a = 2*pi-a; } b = asin(1.0*d/dis); p.l = a-b; p.r = a+b; } double dist(double x, double y) { return sqrt(x*x+y*y); } int main() { int t; int n; double d; int i, j; int ct; double d1; scanf("%d", &t); while(t--) { scanf("%d %lf", &n, &d); for (i=0; i<n; i++) { scanf("%lf %lf", &pt[i].x, &pt[i].y); d1 = dist(pt[i].x, pt[i].y); if (d1<=d) { i--; n--; } else set(pt[i], d, d1); } sort(pt, pt+n, cmp); for (i=n; i<2*n; i++) { pt[i].l = pt[i-n].l+2*pi; pt[i].r = pt[i-n].r+2*pi; } int ans = 1000000; for (j=0; j<n; j++) { ct = 1; double s = pt[j].r; for (i=1+j; i<n+j; i++) { if (s<pt[i].l) { ct++; s = pt[i].r; } else { s = min(s, pt[i].r); } } ans = min(ans, ct); } if (ans==1000000) ans = 0; printf("%d\n", ans); } return 0; }