题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3126
题意:
有N个人,每个人已知一个坐标,有一个攻击半径,每次攻击完之后需要休息t时间才能下一次攻击,有m个敌人,然后有K颗树,当一个敌人位于某一个人攻击范围之内,并且他们线段连线上没有树时,才能进行攻击,问最少需要多少时间将所有敌人消灭。
分析:
先预处理出每个人能攻击到的敌人,
二分时间ans,
源点向每个人连一条容量为ans/v[i]+1的边,
每个人向他能攻击到的敌人连一条容量为1的边,
每个敌人向汇点连一条容量为1的边,
跑一次最大流,
如果流量为m,说明敌人可以被全部消灭,
此时可以考虑减小时间,否则增加时间。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; typedef double db; const db eps=1e-7; const int MAXN=1005; const int MAXM=100005; const int INF=0x3f3f3f3f; struct Edge { int to,next,cap,flow; }edge[MAXM]; int tol,head[MAXN]; int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN]; void init() { tol=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw=0) { edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u]; edge[tol].flow=0; head[u]=tol++; edge[tol].to=u; edge[tol].cap=rw; edge[tol].next=head[v]; edge[tol].flow=0; head[v]=tol++; } int sap(int st,int ed,int N) { memset(gap,0,sizeof(gap)); memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); int u=st; pre[u]=-1; gap[0]=N; int ans=0; while(dep[st]<N) { if(u==ed) { int Min=INF; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow+=Min; edge[i^1].flow-=Min; } u=st; ans+=Min; continue; } bool flag=0; int v; for(int i=cur[u];i!=-1;i=edge[i].next) { v=edge[i].to; if(edge[i].cap-edge[i].flow && dep[v]+1==dep[u]) { flag=1; cur[u]=pre[v]=i; break; } } if(flag) { u=v; continue; } int Min=N; for(int i=head[u];i!=-1;i=edge[i].next) if(edge[i].cap-edge[i].flow && dep[edge[i].to]<Min) { Min=dep[edge[i].to]; cur[u]=i; } gap[dep[u]]--; if(!gap[dep[u]])return ans; dep[u]=Min+1; gap[dep[u]]++; if(u!=st)u=edge[pre[u]^1].to; } return ans; } struct Point { db x,y; Point(){} Point(db _x,db _y):x(_x),y(_y){} Point operator + (const Point &t)const { return Point(x+t.x,y+t.y); } Point operator - (const Point &t)const { return Point(x-t.x,y-t.y); } Point operator * (const db &t)const { return Point(x*t,y*t); } db operator * (const Point &t)const { return x*t.x+y*t.y; } db operator ^ (const Point &t)const { return x*t.y-y*t.x; } db len() { return sqrt(x*x+y*y); } }p[205]; struct Line { Point s,e; Line(){} Line(Point _s,Point _e):s(_s),e(_e){} }; Point PTS(Point P,Line L) { Point result; db t=((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s)); if(t>=0 && t<=1) { result=L.s+(L.e-L.s)*t; } else { if((P-L.s).len()<(P-L.e).len())result=L.s; else result=L.e; } return result; } struct Circle { Point o; db r; Circle(){} Circle(Point _o,db _r):o(_o),r(_r){} }c[205],tr[205]; int v[205]; vector<pair<int,int> >e; int main() { int T; scanf("%d",&T); while(T--) { int n,m,k; scanf("%d%d%d",&n,&m,&k); int Max=0; for(int i=1;i<=n;i++) scanf("%lf%lf%lf%d",&c[i].o.x,&c[i].o.y,&c[i].r,&v[i]); for(int i=1;i<=m;i++) scanf("%lf%lf",&p[i].x,&p[i].y); for(int i=1;i<=k;i++) scanf("%lf%lf%lf",&tr[i].o.x,&tr[i].o.y,&tr[i].r); for(int i=1;i<=n;i++) Max=max(Max,v[i]); e.clear(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if((c[i].o-p[j]).len()<c[i].r+eps) { bool isok=1; for(int t=1;t<=k;t++) if((PTS(tr[t].o,Line(c[i].o,p[j]))-tr[t].o).len()<tr[t].r+eps) isok=0; if(isok) e.push_back(make_pair(i,n+j)); } int l=0,r=(m-1)*Max+2; while(l<r) { int tt=(l+r)>>1; init(); for(int i=1;i<=n;i++) addedge(0,i,tt/v[i]+1); for(int i=0;i<(int)e.size();i++) addedge(e[i].first,e[i].second,1); for(int i=1;i<=m;i++) addedge(n+i,n+m+1,1); if(sap(0,n+m+1,n+m+2)<m)l=tt+1; else r=tt; } printf("%d\n",(l==(m-1)*Max+2 ? -1 : l)); } return 0; }