TYVJ 1935 拆点网络流

思路:
就是一个多重匹配

把每个防御塔拆成
拆成第j次 发射的导弹
跑个网络流

//By SiriusRen
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 555555
int n,m,t1,t2,v,ed=4000;
double l=0,r=500000,mid,base;
struct Node{double x,y;}army[66],tower[66];
struct Dinic{
    int first[4005],next[N],v[N],w[N],vis[N],tot;
    void init(){memset(first,-1,sizeof(first)),tot=0;}
    void add(int x,int y,int z){Add(x,y,z),Add(y,x,0);}
    void Add(int x,int y,int z){w[tot]=z,v[tot]=y,next[tot]=first[x],first[x]=tot++;}
    bool tell(){
        memset(vis,-1,sizeof(vis)),vis[0]=0;
        queue<int>q;q.push(0);
        while(!q.empty()){
            int t=q.front();q.pop();
            for(int i=first[t];~i;i=next[i])
                if(w[i]&&vis[v[i]]==-1)
                    vis[v[i]]=vis[t]+1,q.push(v[i]);
        }
        return vis[ed]!=-1;
    }
    int zeng(int x,int y){
        if(x==ed)return y;
        int r=0;
        for(int i=first[x];~i&&y>r;i=next[i])
            if(w[i]&&vis[v[i]]==vis[x]+1){
                int t=zeng(v[i],min(w[i],y-r));
                w[i]-=t,w[i^1]+=t,r+=t;
            }
        if(!r)vis[x]=-1;
        return r;
    }
    int flow(){
        int jy,ans=0;
        while(tell())while(jy=zeng(0,0x3ffffff))ans+=jy;
        return ans;
    }
}dinic;
double dis(Node a,Node b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main(){
    scanf("%d%d%d%d%d",&n,&m,&t1,&t2,&v);
    for(int i=1;i<=m;i++)scanf("%lf%lf",&army[i].x,&army[i].y);
    for(int i=1;i<=n;i++)scanf("%lf%lf",&tower[i].x,&tower[i].y);
    while(r-l>1e-7){
        mid=(l+r)/2;
        dinic.init();
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)
                dinic.add(0,i+j*60,1);
        for(int i=1;i<=n;i++){
            base=1.0*t1/60;
            for(int j=0;j<m;j++){
                for(int k=1;k<=m;k++)
                    if(base+dis(tower[i],army[k])/v<mid)
                        dinic.add(i+j*60,3800+k,1);
                base+=t2+1.0*t1/60;
            }
        }
        for(int i=1;i<=m;i++)dinic.add(3800+i,3900+i,1),dinic.add(3900+i,4000,1);
        if(dinic.flow()==m)r=mid;
        else l=mid;
    }
    printf("%.6f\n",mid);
}

转载于:https://www.cnblogs.com/SiriusRen/p/6532142.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值