链接:https://cn.vjudge.net/problem/HDU-3126
题意:多组样例,n个巫师,m个敌人,k颗树。巫师有攻击距离和冷却时间,树有半径。若敌人在巫师的攻击范围外,或者巫师和敌人之间被树挡着,都不可攻击。问巫师消灭所有敌人的最少时间。
思路:首先,巫师消灭敌人的个数和时间是成正比的,也就是说是单调的。这满足二分的要求,考虑二分枚举时间T,那么巫师(i)可以消灭敌人的个数为,(加一是因为消灭第一个人不需要冷却时间,并且数据中应该没有t为0的情况。)每次跑一遍最大流检验是否可以全部消灭敌人即可。至于实现,预处理出每个巫师可以消灭的敌人。
1、巫师(i)与源点建边,容量为。
2、巫师(u)与可消灭的敌人建边(v),容量为1。
3、敌人(i)与汇点(t)连边,容量为1。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 610;
const int M = 1e5+10;
const double eps = 1e-7;
const int inf =0x3f3f3f3f;
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
struct Point
{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
Point operator -(const Point& b)const//相减
{
return Point(x-b.x,y-b.y);
}
double operator ^(const Point& b)const//叉乘
{
return x*b.y-y*b.x;
}
double operator *(const Point& b)const//点乘
{
return x*b.x+y*b.y;
}
};
struct Line{ Point s,e; Line(){} Line(Point _s,Point _e){ s = _s; e = _e; } };
struct character { double x,y,r; int t; }li[210],wi[210],tr[210];
double dis(Point a,Point b){ return sqrt((a-b)*(a-b)); }
Point NearestPointToLineSeg(Point P,Line L)
{
Point result;
double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
if(t >= 0 && t <= 1){ result.x = L.s.x + (L.e.x - L.s.x)*t; result.y = L.s.y + (L.e.y - L.s.y)*t; }
else{ if(dis(P,L.s) < dis(P,L.e)) result = L.s; else result = L.e; }
return result;
}
//点p0到线段p1p2的距离
double pointtoseg(Point p0,Point p1,Point p2){ return dis(p0,NearestPointToLineSeg(p0,Line(p1,p2))); }
vector <int> ve[210];
int in[210];
struct node
{
int to,ca,nxt;
}g[M];
int head[N],cnt,s,t;
int deep[N],cur[N];
int n,m,k;
void getve()
{
for(int i=1;i<=n;i++) ve[i].clear();
for(int i=1;i<=m;i++) in[i]=0;
bool no;
double temp;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(sgn(dis(Point(wi[j].x,wi[j].y),Point(li[i].x,li[i].y))-li[i].r)>0) continue;
no=0;
for(int ii=1;ii<=k;ii++)
if(pointtoseg(Point(tr[ii].x,tr[ii].y),Point(li[i].x,li[i].y),Point(wi[j].x,wi[j].y))<=tr[ii].r)
{
no=1; break;
}
if(!no) in[j]++,ve[i].push_back(j);
}
}
void Init()
{
cnt=0;
s=0; t=n+m+1;
for(int i=s;i<=t;i++)
head[i]=-1;
}
void add(int u,int v,int ca)
{
g[cnt]=node{v,ca,head[u]},head[u]=cnt++;
}
bool bfs()
{
queue<int> q;
for(int i=s;i<=t;i++)
deep[i]=0;
int u,v;
deep[s]=1;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
if(u==t) return 1;
for(int i=head[u];~i;i=g[i].nxt)
{
v=g[i].to;
if(!deep[v]&&g[i].ca>0)
{
deep[v]=deep[u]+1;
q.push(v);
}
}
}
return deep[t]!=0;
}
int dfs(int u,int flow)
{
if(u==t||!flow) return flow;
int ans=0,nowflow,v;
for(int& i=cur[u];~i;i=g[i].nxt)
{
v=g[i].to;
if(deep[v]==deep[u]+1&&g[i].ca>0)
{
nowflow=dfs(v,min(flow,g[i].ca));
if(nowflow)
{
ans+=nowflow;
flow-=nowflow;
g[i].ca-=nowflow;
g[i^1].ca+=nowflow;
if(!flow) break;
}
}
}
if(!ans) deep[u]=0;
return ans;
}
void buildg(int x)
{
Init();
for(int i=1;i<=n;i++)
add(s,i,li[i].t?x/li[i].t+1:m),add(i,s,0);
for(int i=1;i<=n;i++)
for(int j=0;j<ve[i].size();j++)
add(i,n+ve[i][j],1),add(n+ve[i][j],i,0);
for(int i=1;i<=m;i++)
add(i+n,t,1),add(t,i+n,0);
}
bool dinic()
{
int maxflow=0,flow;
while(bfs())
{
for(int i=s;i<=t;i++)
cur[i]=head[i];
while(flow=dfs(s,inf))
maxflow+=flow;
}
return maxflow==m;
}
int main(void)
{
int t,l,r,mid,ans,maxt;
scanf("%d",&t);
while(t--)
{
maxt=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf%d",&li[i].x,&li[i].y,&li[i].r,&li[i].t),maxt=max(t,li[i].t);
for(int i=1;i<=m;i++)
scanf("%lf%lf",&wi[i].x,&wi[i].y);
for(int i=1;i<=k;i++)
scanf("%lf%lf%lf",&tr[i].x,&tr[i].y,&tr[i].r);
getve();
bool no=0;
for(int i=1;i<=m;i++) if(!in[i]){ no=1; break; }
if(no){ puts("-1"); continue; }
l=0,r=2*m*maxt,ans=-1;
while(l<=r)
{
mid=(l+r)>>1;
buildg(mid);
if(dinic())
{
r=mid-1;
ans=mid;
}
else l=mid+1;
}
printf("%d\n",ans);
}
return 0;
}