题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6603
题目大意是:给你n个点,g的圆 圆给的是圆心。然后在这n个点求一个凸包,在凸包不相邻的两点并且与圆不相交找到直线。
找到凸包上所有不相交直线的最大数。
这里判断直线和圆的关系使用了面积判断,画个图就知道了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const double eps = 1e-10;
double dcmp(double x) {
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
struct Point {
double x, y;
Point(double x=0, double y=0):x(x),y(y) {}
}b[401];
typedef Point Vector;
Vector operator - (const Point& A, const Point& B) {
return Vector(A.x-B.x, A.y-B.y);
}
double Cross(const Vector& A, const Vector& B) {
return A.x*B.y - A.y*B.x;
}
double distance(double x1,double y1,double x2,double y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double Dot(const Vector& A, const Vector& B) {
return A.x*B.x + A.y*B.y;
}
bool operator < (const Point& p1, const Point& p2) {
return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y);
}
bool operator == (const Point& p1, const Point& p2) {
return p1.x == p2.x && p1.y == p2.y;
}
bool SegmentProperIntersection(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {
double c1 = Cross(a2-a1,b1-a1), c2 = Cross(a2-a1,b2-a1),
c3 = Cross(b2-b1,a1-b1), c4=Cross(b2-b1,a2-b1);
return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
bool OnSegment(const Point& p, const Point& a1, const Point& a2) {
return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0;
}
// 点集凸包
// 如果不希望在凸包的边上有输入点,把两个 <= 改成 <
// 如果不介意点集被修改,可以改成传递引用
vector<Point> ConvexHull(vector<Point> p) {
// 预处理,删除重复点
sort(p.begin(), p.end());
p.erase(unique(p.begin(), p.end()), p.end());
int n = p.size();
int m = 0;
vector<Point> ch(n+1);
for(int i = 0; i < n; i++) {
while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
ch[m++] = p[i];
}
int k = m;
for(int i = n-2; i >= 0; i--) {
while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
ch[m++] = p[i];
}
if(n > 1) m--;
ch.resize(m);
return ch;
}
int e[500][500],f[405][405];
int main(){
int t;
scanf("%d",&t);
double x,y;
int n,g,r;
while(t--){
int ans=0;
scanf("%d%d%d",&n,&g,&r);
vector<Point> v;
for(int i=0;i<n;i++){
scanf("%lf %lf",&x,&y);
v.push_back({x,y});
}
v = ConvexHull(v);
for(int i=1;i<=g;i++){
scanf("%lf %lf",&b[i].x,&b[i].y);
}
int len=v.size();
//得到不与圆相交和相切的不相邻2点 标记为1为可行直线
for(int i=0;i<len;i++){
for(int j=i+1;j<len;j++){
if(i==0&&j==len-1){
continue;
}
e[i+1][j+1]=e[j+1][i+1]=1;
double dis = distance(v[i].x,v[i].y,v[j].x,v[j].y);
for(int k=1;k<=g;k++){
double cha = abs( Cross(v[i]-v[j],(v[i]-b[k])) );
if(cha + eps <= 1.0*dis*r){
e[i+1][j+1]=e[j+1][i+1]=0;
break;
}
}
}
}
//最后区间dp 找到不相交的 最大直线数
for(int i=2;i<=len-2;i++){
for(int j=1;j<=len;j++){
int nex = (i+j-1)%n+1,res=0;
res = max(f[j][i-1] ,f[j%len+1][i-1]);
f[j][i] = e[j][nex] + res;
ans = max(ans,f[j][i]);
}
}
printf("%d\n",ans);
memset(e,0,sizeof(e));
}
}