Description
从APIO回来之后,XX便迷上了“战火星空”这个游戏。
原版战火星空中,有一架小飞机和一个Boss,玩家控制小飞机来对Boss进行射击。然而,这种“一对一”的游戏已经让XX乏味,于是XX基于原版战火星空,将其加强创造了一款新版战火星空。
新版战火星空中,有N个Boss和M架小飞机。在游戏过程中,Boss的位置不会改变,而小飞机在从(Sx, Sy)到(Ex, Ey)的线段以速度V匀速飞行,并在到达终点后从地图上消失;小飞机的子弹具有R的射程,在任意时刻,小飞机可以向在射程内的Boss射击;而为了使实力更加均衡,游戏还规定在任意时刻,每个Boss只能被一架小飞机作为目标射击;每架小飞机也有一个能量值E的限制,若某时刻小飞机向K个Boss射击,则每秒需要消耗K个单位的能量,所有能量消耗完之后小飞机不再能够进行射击。
在游戏开始前,XX知道了所有Boss的位置,以及每架小飞机的飞行路线以及各项属性,他想知道所有Boss被攻击的总时间最大是多少,你能帮助他吗?
Input
第一行包含两个整数N,M,分别表示Boss和小飞机的个数。
接下来N行,每行一个正整数点坐标(x, y),表示Boss所在的位置。
接下来M行,每行七个正整数:Sx, Sy, Ex, Ey, V, R, E,表示每架小飞机的运动路线、速度、射程以及能量值。
Output
输出一个实数,表示所有Boss被攻击的最大总时间,保留6位小数。
Sample Input
样例1:
1 1
2 2
1 1 5 3 2 1 2
样例2:
2 4
12 10
7 5
10 10 12 10 1 1 3
6 1 8 10 1 2 3
3 6 8 2 5 3 1
42 42 42 42 6 6 6
Sample Output
样例1:
0.894427
样例2:
4.983771
HINT
对于30%的数据,保证每个Boss在任意时刻只在最多一架小飞机的射程范围内。对于100%的数据,1≤N,M≤20,输入的所有数均为正整数,且不超过1000。
Source
如果我们不考虑计算几何的问题的话,单纯的最大流建图还是非常好想的.
考虑对每个飞机和时间段+1个点,建立源汇,源点向飞机连流量e的边,飞机向boss连流量无穷大的边,时间段向可攻击时间点连时间长度的边,然后向汇点连inf的边,跑最大流.
然后最大的问题就是几何,需要线段和圆求交,然后就有比较多的细节要考虑了..
而且这题似乎还卡精度.
因为是暑假的考试题,直接拉来数据自己测完,交上去1A了.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define eps 1e-10
#define N 25
#define C N*N*5
#define MAXN N*N*N*5
#define MAXM MAXN*10
using namespace std;
int n,m,tp,top,S,T,size;
double ans;
int map[N][N];
struct point
{
double x,y;
point(double _x=0,double _y=0):
x(_x),y(_y){}
};
typedef point Vector;
Vector boss[N],s[N][2];
double v[N],r[N],E[N],tim[N];
inline Vector operator + (const Vector& A,const Vector& B) { return Vector(A.x+B.x,A.y+B.y); }
inline Vector operator - (const Vector& A,const Vector& B) { return Vector(A.x-B.x,A.y-B.y); }
inline Vector operator * (const Vector& A,double k) { return Vector(A.x*k,A.y*k); }
inline Vector operator / (const Vector& A,double k) { return Vector(A.x/k,A.y/k); }
inline double dot(const Vector& A,const Vector& B) { return A.x*B.x+A.y*B.y; }
inline double cross(const Vector& A,const Vector& B) { return A.x*B.y-A.y*B.x; }
inline double length(const Vector& A) { return sqrt(A.x*A.x+A.y*A.y); }
inline Vector rot(const Vector &A) { return Vector(-A.y,A.x); }
inline Vector unit(const Vector &A) { return A/length(A); }
struct line
{
Vector p,v;
line (point _p=point(0,0),point _v=point(0,0)):
p(_p),v(_v){}
};
inline Vector linecross(const line& A,const line& B)
{
Vector u=A.p-B.p;
double t=cross(B.v,u)/cross(A.v,B.v);
return A.p+A.v*t;
}
inline Vector getcross(const line& l,const Vector& B,double V,double R)
{
Vector mid=linecross(l,line(B,rot(l.v)));
double t=length(mid-B),len;
if (t+eps>R) return Vector(1e50,-1e50);
t=sqrt(R*R-t*t);len=length(mid-l.p);
if (dot(mid-l.p,l.v)<0) len=-len;
return Vector((len-t)/V,(len+t)/V);
}
struct node
{
double pos;
int u,v,w;
node (double _pos=0,int _u=0,int _v=0,int _w=0):
pos(_pos),u(_u),v(_v),w(_w){}
inline bool operator <(const node& a)const { return pos<a.pos; }
}sta[C];
struct edge { int st,to; double c; edge *next,*rev; }e[MAXM],*prev[MAXN];
inline void insert(int u,int v,double c) { e[++top].to=v;e[top].st=u;e[top].c=c;e[top].next=prev[u];prev[u]=&e[top]; }
inline void add(int u,int v,double c) { insert(u,v,c);insert(v,u,0.0);prev[u]->rev=prev[v];prev[v]->rev=prev[u]; }
int dis[MAXN],cnt[MAXN];
double ISAP()
{
edge *E[MAXN],*rep[MAXN];int now=S;double ret=0;
memset(cnt,0,sizeof(cnt));memset(dis,0,sizeof(dis));
for (int i=1;i<=size;i++) E[i]=prev[i];cnt[0]=size;
while (dis[S]<=size)
{
edge *i;bool b=0;
for (i=E[now];i;i=i->next) if (i->c>eps&&dis[i->to]+1==dis[now]) { b=1;E[now]=i;break; }
if (b)
{
rep[now=i->to]=i;
if (now==T)
{
double minn=1e60;
for (int i=T;i!=S;i=rep[i]->st) minn=min(rep[i]->c,minn);
for (int i=T;i!=S;i=rep[i]->st) rep[i]->c-=minn,rep[i]->rev->c+=minn;
ret+=minn;now=S;
}
}
else
{
if (!(--cnt[dis[now]])) break;
int mind=size+1;E[now]=prev[now];
for (edge *j=prev[now];j;j=j->next) if (j->c>eps) mind=min(mind,dis[j->to]);
dis[now]=mind+1;++cnt[dis[now]];
if (now!=S) now=rep[now]->st;
}
}
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lf%lf",&boss[i].x,&boss[i].y);
for (int i=1;i<=m;i++)
scanf("%lf%lf%lf%lf",&s[i][0].x,&s[i][0].y,&s[i][1].x,&s[i][1].y),
scanf("%lf%lf%lf",&v[i],&r[i],&E[i]),tim[i]=length(s[i][1]-s[i][0])/v[i];
for (int i=1;i<=m;i++)
{
line t=line(s[i][0],s[i][1]-s[i][0]);
for (int j=1;j<=n;j++)
{
Vector tmp=getcross(t,boss[j],v[i],r[i]);
tmp.x=max(tmp.x,0.0);tmp.y=min(tmp.y,tim[i]);
if (tmp.x<tmp.y+eps) sta[++tp]=node(tmp.x,i,j,1),sta[++tp]=node(tmp.y,i,j,-1);
}
}
sort(sta+1,sta+tp+1);int cost=0;S=m+1;T=S+1;size=T;
for (int i=1;i<=m;i++) add(S,i,E[i]);
for (int i=1;i<=tp;i++)
{
cost+=sta[i].w;map[sta[i].u][sta[i].v]+=sta[i].w;
if (i!=tp&&(sta[i].pos+eps<sta[i+1].pos))
{
if (!cost) continue;
double t=sta[i+1].pos-sta[i].pos;
for (int j=1;j<=n;j++)
{
bool flag=0;
for (int k=1;k<=m;k++)
if (map[k][j])
{
if (!flag) flag=1,++size,add(size,T,t);
add(k,size,1e9+10);
}
}
}
}
ans=ISAP();printf("%.6f\n",ans);
}