【题目】
原题地址
平面内有
n
n
n个
boss
\text{boss}
boss和
m
m
m架飞机,飞机从
(
s
x
,
s
y
)
(s_x,s_y)
(sx,sy)以
V
V
V的速度匀速运动到
(
E
x
,
E
y
)
(E_x,E_y)
(Ex,Ey),并在到达终点后消失,飞机子弹有
R
R
R的射程,有
E
E
E的能量。一个时刻小飞机可以向任意个
boss
\text{boss}
boss射击,射击
k
k
k个将会消耗
k
k
k个单位的能量,能量消耗完将不能射击。一个
boss
\text{boss}
boss同时只能受到一架飞机的射击。
求所有
boss
\text{boss}
boss被攻击总时间最大值。
n
,
m
≤
20
n,m\leq 20
n,m≤20,所有数字为正整数且
<
1000
<1000
<1000
【解题思路】
首先不考虑计算几何的部分,网络流的部分比较简单,就是
S
S
S到每个飞机连容量,每个能攻击到
boss
\text{boss}
boss的时间段连
T
T
T,容量为时间长度,然后由飞机向时间段连边即可。
于是我们只要求出对于每个 boss \text{boss} boss每个飞机能攻击到的时间段即可。
观察到飞机的飞行路线是一条线段,攻击范围是一个半径为 r r r的圆,那么其实可以枚举每个 boss \text{boss} boss,以 boss \text{boss} boss为圆心求出与这条线段的交点,进而求出可攻击时间。
圆和线段求交就可以直接作法向量求出垂足,然后勾股求出距离之后,特判一下方向就可以了,然后再和这个飞机的最短最长时间取一下交即可。
想作死点斜式写个二元一次方程求根也是可以的。
初始旋转坐标系可以避免很多特判。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int N=25,M=N*N*N*N*2;
const int INF=0x3f3f3f3f;
const db eps=1e-10,DNF=(db)1e50,ep=0.1,PI=acos(-1);
int n,m,cnt,nod;
int mp[N][N];
db V[N],R[N],E[N],lim[N];
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
namespace Dinic
{
int tot,S,T,head[M],cur[M],dis[M];
queue<int>q;
struct Tway{int v,nex;db w;}e[M];
void add(int u,int v,db w)
{
//printf("add:%d %d %lf\n",u,v,w);
e[++tot]=(Tway){v,head[u],w};head[u]=tot;
e[++tot]=(Tway){u,head[v],0};head[v]=tot;
}
bool bfs()
{
for(int i=0;i<=nod;++i) dis[i]=-1,cur[i]=head[i];
while(!q.empty()) q.pop();
q.push(S);dis[S]=0;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].v;
//printf("%d %d %d %d %lf\n",u,v,dis[u],dis[v],e[i].w);
if(e[i].w>eps && !~dis[v]) dis[v]=dis[u]+1,q.push(v);
}
}
return ~dis[T];
}
db dfs(int x,db flow)
{
if(x==T || flow<eps) return flow;
db used=0,w;
for(int &i=cur[x];i;i=e[i].nex)
{
int v=e[i].v;
if(dis[v]==dis[x]+1 && (w=dfs(v,min(flow-used,e[i].w)))>eps)
{
e[i].w-=w;e[i^1].w+=w;used+=w;
if(used+eps>=flow) break;
}
}
return used;
}
db dinic(){db res=0;while(bfs()) res+=dfs(S,INF);printf("%.6lf\n",res);}
};
using namespace Dinic;
namespace Geometry
{
struct node
{
db x,y;
node(){}
node(db x,db y):x(x),y(y){}
void turn(db deg)
{
deg=deg*PI/180;
db tx=cos(deg)*x-sin(deg)*y;
db ty=sin(deg)*x+cos(deg)*y;
x=tx;y=ty;
}
void in(){x=read();y=read();turn(ep);}
void out(){printf("%lf %lf\n",x,y);}
}a[N][2],b[N];
struct line
{
node a,b;
line(){}
line(node a,node b):a(a),b(b){}
};
struct data
{
int u,v,w;db pos;
data(){}
data(db pos,int u,int v,int w):pos(pos),u(u),v(v),w(w){}
void out(){printf("%lf %d %d %d\n",pos,u,v,w);}
}s[M];
bool cmp(const data&a,const data &b){return a.pos<b.pos;}
node operator + (const node&a,const node&b){return node(a.x+b.x,a.y+b.y);}
node operator - (const node&a,const node&b){return node(a.x-b.x,a.y-b.y);}
node operator * (const node&a,db x){return node(a.x*x,a.y*x);}
node rotate(const node&a){return node(-a.y,a.x);}
db getlen(const node&a){return sqrt(a.x*a.x+a.y*a.y);}
db dot(const node&a,const node&b){return a.x*b.x+a.y*b.y;}
db css(const node&a,const node&b){return a.x*b.y-a.y*b.x;}
node linecross(const line&a,const line&b)
{
node x=a.a-b.a;
db t=css(b.b,x)/css(a.b,b.b);
return a.a+a.b*t;
}
node cross(const line&l,const node&p,db v,db r)
{
node mid=linecross(l,line(p,rotate(l.b)));
db t=getlen(mid-p),len;
if(t+eps>r) return node(DNF,-DNF);
t=sqrt(r*r-t*t);len=getlen(mid-l.a);
if(dot(mid-l.a,l.b)<0) len=-len;
return node((len-t)/v,(len+t)/v);
}
};
using namespace Geometry;
void init()
{
n=read();m=read();
for(int i=1;i<=n;++i) b[i].in();
for(int i=1;i<=m;++i)
{
a[i][0].in();a[i][1].in();
V[i]=read();R[i]=read();E[i]=read();
lim[i]=getlen(a[i][1]-a[i][0])/V[i];
}
for(int i=1;i<=m;++i)
{
line t=line(a[i][0],a[i][1]-a[i][0]);
for(int j=1;j<=n;++j)
{
node t2=cross(t,b[j],V[i],R[i]);
t2.x=max(t2.x,0.0);t2.y=min(t2.y,lim[i]);
if(t2.x<t2.y+eps) s[++cnt]=data(t2.x,i,j,1),s[++cnt]=data(t2.y,i,j,-1);
}
}
sort(s+1,s+cnt+1,cmp);
//for(int i=1;i<=cnt;++i) s[i].out();
}
void getmap()
{
int cst=0;S=m+1;T=m+2;tot=1;nod=T;
//printf("S:%d T:%d\n",S,T);
for(int i=1;i<=m;++i) add(S,i,E[i]);
for(int i=1;i<=cnt;++i)
{
cst+=s[i].w;mp[s[i].u][s[i].v]+=s[i].w;
if(i^cnt && (s[i].pos+eps<s[i+1].pos))
{
if(!cst) continue;
db t=s[i+1].pos-s[i].pos;
for(int j=1;j<=n;++j)
{
bool fg=0;
for(int k=1;k<=m;++k) if(mp[k][j])
{
if(!fg) add(++nod,T,t),fg=1;
add(k,nod,INF);
}
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ2864.in","r",stdin);
freopen("BZOJ2864.out","w",stdout);
#endif
init();getmap();dinic();
return 0;
}
【总结】
这是一道写了2.5h的线段与圆交。。。