题意:
WJJ喜欢“魔兽争霸”这个游戏。在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵。我们认为,巫妖和小精灵都可以看成是平面上的点。 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵。 在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放。不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以杀死一个小精灵。 现在巫妖的头目想知道,若从0时刻开始计算,至少需要花费多少时间,可以杀死所有的小精灵?
题解:
几何+二分+网络流。
这题很容易想到二分+网络流求答案。
但是难在怎么判断巫妖能不能打到011
注意,树木很粗壮。
首先有三种情况。
好吧也可以说是两种。
点到直线距离公式:
d=|x0+By0+CA2+B2−−−−−−−√|
详细见百度。
对于第一种情况,直接带公式就行了。
但第二种情况就应该取到端点的最短值。
所以我们还要求出点到两端点的较大值。
勾股求第三边。
假如这条边的长度小于线段长,那么在是第一种情况,否则为第二种情况。
然后就愉快的建图+跑流了。
code:
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
struct node{
int x,y,next,c,other;
}a[2500000];int last[500],len=0;
int h[500],s[500],st,ed;
void ins(int x,int y,int c)
{
int k1=++len;
a[len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
int k2=++len;
a[len].x=y;a[len].y=x;a[len].c=0;
a[len].next=last[y];last[y]=len;
a[k1].other=k2;a[k2].other=k1;
}
bool bt_h()
{
memset(h,0,sizeof(h));
int l=1,r=2;s[l]=st;h[st]=1;
while(l!=r)
{
int x=s[l];
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(h[y]==0&&a[i].c>0) h[y]=h[x]+1,s[r++]=y;
}
l++;
}
return h[ed]!=0;
}
int findflow(int x,int f)
{
if(x==ed) return f;
int t,ans=0;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(h[x]+1==h[y]&&a[i].c>0&&ans<f)
{
ans+=(t=findflow(y,min(a[i].c,f-ans)));
a[i].c-=t;a[a[i].other].c+=t;
}
}
if(ans==0) h[x]=0;
return ans;
}
struct point{
int x,y;
}p1[210],p2[210],p3[210];
int R[210];
struct NODE{
int r,t;
}wy[210];
int n,m,k;
bool check[210][210],kill[210];
/*int multi(point p1,point p2,point p0)
{
int x1=p1.x-p0.x,x2=p2.x-p0.x;
int y1=p1.y-p0.y,y2=p2.y-p0.y;
return x1*y2-x2*y1;
}*/
double cz(int A,int B,int C,point p){return abs((double)(A*p.x+B*p.y+C)/sqrt((double)A*A+(double)B*B));}
double dis(point p1,point p2){return sqrt((double)(p1.x-p2.x)*(p1.x-p2.x)+(double)(p1.y-p2.y)*(p1.y-p2.y));}
bool shoot(point p1,point p2,int r)
{
double LEN=dis(p1,p2);
if(LEN>(double)r) return false;
int A=p2.y-p1.y,B=p1.x-p2.x;
int C=-(A*p1.x+B*p1.y);
for(int i=1;i<=n;i++)
{
/*double tmp;
if(multi(p1,p2,p3[i])==0)
else*/
double aa=cz(A,B,C,p3[i]),cc=max(dis(p1,p3[i]),dis(p2,p3[i])),t;
if(sqrt(cc*cc-aa*aa)>LEN) t=min(dis(p1,p3[i]),dis(p2,p3[i]));
else t=aa;
if(t<R[i]) return false;
}
return true;
}
bool CHECK(int t)
{
memset(last,0,sizeof(last));len=0;
st=0;ed=n+m+1;
for(int i=1;i<=n;i++)
{
ins(st,i,t/wy[i].t+1);
for(int j=1;j<=m;j++)
if(check[i][j]) ins(i,j+n,1);
}
for(int i=1;i<=m;i++) ins(i+n,ed,1);
int ans=0;
while(bt_h()) ans+=findflow(st,999999999);
return ans==m;
}
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=n;i++) scanf("%d %d %d %d",&p1[i].x,&p1[i].y,&wy[i].r,&wy[i].t);
for(int i=1;i<=m;i++) scanf("%d %d",&p2[i].x,&p2[i].y);
for(int i=1;i<=k;i++) scanf("%d %d %d",&p3[i].x,&p3[i].y,&R[i]);
memset(check,false,sizeof(check));
memset(kill,false,sizeof(kill));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(shoot(p1[i],p2[j],wy[i].r)) check[i][j]=true,kill[j]=true;
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) printf("%d ",check[i][j]);
printf("\n");
}*/
for(int i=1;i<=m;i++)
if(!kill[i]){printf("-1");return 0;}
int l=0,r=5000000,ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if(CHECK(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d",ans);
}