【BZOJ2864】战火星空

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);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值