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;
}