hdu6603 Azshara’s deep sea(2019hdu多校第三场1001)
【题目描述】
传送带
汗!感觉读题时间比想题时间还长
大概意思是wood stick(可视为顶点)围成了一个battle field,players可以在这个围成的battle field中(含边界)活动,另外这个区域内还有一些圆,现在有个boss要选若干对player并且把他们放在顶点,并用直线把他们连在一起,这些连线要满足两个条件:1)不可以和区域内的圆相切或相交,2)两两之间不可以相交(但端点可以相同)3)一对play不可以在相邻的顶点上
求boss最多可以选出多少对player
【思考】
其实就是选若干对不相邻的顶点,不相交,不经过圆。
先维护出一个凸包,预处理每条线段是否不经过圆,对于一条线段check的时间是O(G)(G是圆的个数),这些时间复杂度都不高,所以重点在于选哪些线段使他们两两不相交,有种三角剖分的冲动(也是三角不能相交或交于一边),而且顶点数也不大,所以就用区间dp来解决
转移方程是
dp[i][j]=max{dp[i][j],dp[i][t]+dp[t][j]+rel[i][j]} (i<t<j)
rel是预处理的顶点ij连边是否不经过所有圆
注意t不等于i或j,否则会重复计算
这题计算几何的部分参考了另一篇博客
传送带
这篇博客处理区间dp似乎是把原来的区间延长来得到一个循环,不过还是没有太看懂膜一下大佬
【代码】
#include <iostream>
#include <string.h>
#include <queue>
#include <stdlib.h>
#include <stdio.h>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN=4e2+10;
const double eps=1e-10;
const double pi=acos(-1.0);
const ll INF=0x3f3f3f3f3f3f3f3f;
int T;
int N,R,G;
int dp[MAXN][MAXN];
int rel[MAXN][MAXN];
inline double sqr(double x){
return x*x;
}
inline int dcmp(double x){
if(fabs(x)<eps) return 0;
return x>0?1:-1;
}
struct Point{
double x,y;
Point(){x=0,y=0;}
Point(double _x,double _y):x(_x),y(_y){}
void input(){scanf("%lf%lf",&x,&y);}
void output(){printf("%.2lf %.2lf\n",x,y);}
bool operator ==(const Point &b)const{
return (dcmp(x-b.x)==0&&dcmp(y-b.y)==0);
}
bool operator !=(const Point &b)const{
return !(dcmp(x-b.x)==0&&dcmp(y-b.y)==0);
}
bool operator <(const Point &b)const{
return (dcmp(x-b.x)==0?dcmp(y-b.y)<0:x<b.x);
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
double len2(){
return sqr(x)+sqr(y);
}
double len(){
sqrt(len2());
}
}p[MAXN];
inline double cross(Point a,Point b){
return a.x*b.y-a.y*b.x;
}
inline double dis(Point a,Point b){
Point p=b-a;
return p.len();
}
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e):s(_s),e(_e){}
double length(){
return dis(s,e);
}
};
struct Circle{
Point p;
double r;
Circle(){}
Circle(Point _p,double _r):p(_p),r(_r){}
}c[MAXN];
double point_to_line(Point p,Line a){
return fabs(cross(p-a.s,a.e-a.s)/a.length());
}
void swap(Point &a,Point &b){
Point t=a;a=b;b=t;
}
int relation(Line a,Circle b){
double p=point_to_line(b.p,a);
if(dcmp(p-b.r)==0) return 1;
return (dcmp(p-b.r)<0?2:0);
}
Point tmp[MAXN];
int convex_hull(Point *p,int n,Point *ch){
int m=0;
sort(p,p+n);
for(int i=0;i<n;i++){
while(m>1&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<=0) m--;
tmp[m++]=p[i];
}
int k=m;
for(int i=n-2;i>=0;i--){
while(m>k&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<=0) m--;
tmp[m++]=p[i];
}
if(n>1) m--;
for(int i=0;i<m;i++) ch[i]=tmp[i];
return m;
}
int main(){
scanf("%d",&T);
while(T--){
memset(dp,0,sizeof(dp));
memset(rel,0,sizeof(rel));
scanf("%d%d%d",&N,&G,&R);
for(int i=0;i<N;i++){p[i].input();}
int n=convex_hull(p,N,p);
for(int i=0;i<G;i++){c[i].p.input();c[i].r=R;}
for(int i=0;i<n;i++){
for(int j=i+2;j<n-(i==0);j++){
int flag=1;
for(int k=0;k<G;k++){
if(relation(Line(p[i],p[j]),Circle(c[k]))){
flag=0;
break;
}
}
if(flag==1) rel[i][j]=rel[j][i]=1;
}
}
for(int k=2;k<n;k++)
for(int i=0;i<n-k;i++){
int j=i+k;
for(int t=i+1;t<j;t++)
dp[i][j]=max(dp[i][j],dp[i][t]+dp[t][j]+rel[i][j]);
}
int ans=0;
for(int i=0;i<n;i++)
for(int j=i+2;j<n-(i==0);j++)
ans=max(ans,dp[i][j]);
printf("%d\n",ans);
}
return 0;
}