CodeVS2490 导弹防御塔 【二分答案】【匈牙利】

【题目描述】
 Freda的城堡——
  “Freda,城堡外发现了一些入侵者!”
  “喵…刚刚探究完了城堡建设的方案数,我要歇一会儿嘛lala~”
  “可是入侵者已经接近城堡了呀!”
  “别担心,rainbow,你看呢,这是我刚设计的导弹防御系统的说~”
  “喂…别卖萌啊……”

  Freda控制着N座可以发射导弹的防御塔。每座塔都有足够数量的导弹,但是每座塔每次只能发射一枚。在发射导弹时,导弹需要T1秒才能从防御塔中射出,而在发射导弹后,发射这枚导弹的防御塔需要T2分钟来冷却。
  所有导弹都有相同的匀速飞行速度V,并且会沿着距离最短的路径去打击目标。计算防御塔到目标的距离Distance时,你只需要计算水平距离,而忽略导弹飞行的高度。导弹在空中飞行的时间就是 (Distance/V) 分钟,导弹到达目标后可以立即将它击毁。
  现在,给出N座导弹防御塔的坐标,M个入侵者的坐标,T1、T2和V,你需要求出至少要多少分钟才能击退所有的入侵者。
【题解】
二分+dinic
我们在发射的防御塔和目标之间连一个(双向)边,跑一边看符不符合就行了。
代码如下:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int inf=30000;
const int M=1000000;
const int N=50;
double t[N*N+5][N*N+5];
double t1,t2;
int x[N+5],y[N+5];
int num,head[M+5];
bool flag[M+5];
int match[M+5];
int n,m;
double v;
struct edge
{
    int u,v;
    int next;
    edge(){next=-1;}
}ed[M+5];
void build(int u,int v)
{
    num++;
    ed[num].v=v;
    ed[num].next=head[u];
    head[u]=num;
}
bool dfs(int u)
{
    for(int i=head[u];i!=-1;i=ed[i].v)
    {
        int v=ed[i].v;
        if(!flag[v])
        {
            flag[v]=1;
            if(!match[v]||!dfs(match[v]))
            {
                match[v]=u;
                return true;
            }
        }
    }
    return false;
}
bool check(double T)
{
    num=0;
    memset(head,-1,sizeof(head));
    memset(match,0,sizeof(match));
    int d=(d-T)/(t1+t2)+1;
    for(int i=1;i<=n;i++)
    for(int j=0;j<d;j++)
    {
        double now=t1+(t1+t2)*j;
        for(int k=1;k<=m;k++)
        {
            if(now+t[i][m]<=T)
            {
                build(i+j*n,d*n+k);
                build(d*n+k,j*n+i);
            }
        }
    }
    int ans=0;
    for(int i=1;i<=d*n+m;i++)
    {
        memset(flag,0,sizeof(flag));
        if(dfs(1))ans++;
    }
    return ans>>2==m;
}
double div()
{
    double lf=t1,rg=inf;
    for(int i=1;i<=40;i++)
    {
        double mid=(lf+rg)/2.0;
        if(check(mid))rg=mid;
        else lf=mid;
    }
    return rg;
}
double calc(int x1,int y1,int x2,int y2)
{
    return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
int main()
{
    scanf("%d%d%lf%lf%lf",&n,&m,&t1,&t2,&v);
    t1/=60.0;
    for(int i=1;i<=m;i++)
    scanf("%d%d",&x[i],&y[i]);
    for(int i=1;i<=n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        for(int j=1;j<=m;j++)
        t[i][j]=calc(x[j],y[j],a,b)/v;
    }
    printf("%.6lf\n",div());
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值