题目大意:给定n个点,要求建造尽量少得铁路(从原点发射出的射线),使得所有点到铁路的最短距离小于d。
解题思路:题目可以转化成区间选点问题,即以极角来表示铁轨,然后计算出每个区间可行的极角范围,进行区间选点。
注意:(1)如果点到原点的距离dis<=d的话,不进行考虑,也无法判断,因为没有说直角边大于等于斜边的。
(2)区间有可能在二三象限时重叠,我的处理方法是每次枚举起始点,进行n次选点问题。
(3)因为每次都将区间i的左右区间+2pi后放到最后,忘记考虑s[i].r+2pi 有可能小于 s[m-1].r的情况,所以一直WA。
处理,在初始化区间时,将右区间大于pi的统一左右区间减掉2pi。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int N = 205;
const int INF = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-9;
struct state {
double l, r;
}s[N*2];
int n, m;
double d;
bool cmp(const state& a, const state& b) {
return a.r - b.r < eps;
}
void init () {
double x, y, c, k;
m = 0;
scanf("%d%lf", &n, &d);
for (int i = 0; i < n; i++) {
scanf("%lf%lf", &x, &y);
c = atan2(y, x);
double dis = sqrt(x*x + y*y);
if (d >= dis) continue;
k = asin(d/dis);
s[m].l = c-k; s[m].r = c+k;
if (s[m].r > pi) {
s[m].l -= 2*pi;
s[m].r -= 2*pi;
}
m++;
}
sort(s, s + m, cmp);
for (int i = 0; i < m; i++) {
s[i+m].l = s[i].l + 2*pi;
s[i+m].r = s[i].r + 2*pi;
}
}
int del (state* f) {
int ans = 1;
double tmp = f[0].r;
for (int i = 1; i < m; i++) {
if (tmp - f[i].l > -eps) continue;
else {
tmp = f[i].r;
ans++;
}
}
return ans;
}
int solve () {
if (m == 0) return 0;
int ans = m;
for (int i = 0; i < m; i++) {
ans = min(del(s+i), ans);
}
return ans;
}
int main () {
int cas;
scanf("%d", &cas);
while (cas--) {
init();
printf("%d\n", solve());
}
return 0;
}
原文:http://blog.csdn.net/keshuai19940722/article/details/19415619