ZOJ Missile 3460 (最大流+二分)

题目大意:给定n,m,t1,t2,v分别代表n个导弹发射器,m个物体,发射前的准备时间t1秒,每个导弹发射器发射后经t2分钟才能分社下一个炮弹,速度为v,然后m+n行为m个物体坐标,n行为导弹发射器的坐标.问最后摧毁所有的目标需要的时间是多少。

思路:很明显是最大流的问题。因此还是建图的问题。每个导弹发射器攻击目标可能之前发射了0,1,…m-1次导弹,所以把每个导弹发射器拆成m个,所以共有n*m个发射器。因为每次轰炸一次即可将目标摧毁,所以流量为1 。那么怎么控制求解的时间是最短的呢?这个问题可以转化为求满流并且二分最短的消耗时间。同时将mid作为n*m个导弹发射器和m个目标的联系基础。如果建立他们之间的关系必定是ti[i][j]<=mid.

#include<map>
#include<queue>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#include<algorithm>
#define LL long long
#define inf 0x3f3f3f3f
#define eps 1e-8

const double PI=acos(-1.0);
using namespace std;
int head[100010],la[100010];
int st,ed,cnt,n,m;

struct node{
    int a,b;
}mis[110],aim[110];

double dis[1010][1010],ti[1010][1010];

struct no{
    int to,next,w;
}q[100010];

void bu(int a,int b,int w){
    q[cnt].to = b;
    q[cnt].w = w;
    q[cnt].next = head[a];
    head[a] = cnt++;

    q[cnt].to = a;
    q[cnt].w = w;
    q[cnt].next = head[b];
    head[b] = cnt++;
}

bool bfs(){
    memset(la,-1,sizeof(la));
    la[st] = 0;
    queue<int>Q;
    while(!Q.empty())
        Q.pop();
    Q.push(st);
    while(! Q.empty()){
        int u=Q.front();
        Q.pop();
        for(int i = head[u];i != -1; i = q[i].next){
            int v = q[i].to;
            if(q[i].w && la[v] == -1){
                la[v] = la[u] + 1;
                Q.push(v);
            }
        }
    }
    return la[ed] != -1;
}

int dfs(int x,int f){
    if(x == ed || !f){
        return f;
    }
    int a,tmp = 0;
    for(int i = head[x]; ~ i ;i = q[i].next){
        int u = q[i].to;
        if(la[x]+1 == la[u]  && q[i].w){
            a=dfs(q[i].to,min(q[i].w,f - tmp));
            if(a > 0){
                q[i].w -= a;
                q[i^1].w += a ;
                tmp += a;
                if(tmp == f){
                    break;
                }
            }
        }
    }
    if(!tmp)
        la[x] = -1;
    return tmp;
}

void creat(double mid){
    int i,j;
    for(i = 1;i <= m*n ; ++ i){
        bu(st,i,1);
    }
    for(i = 1;i <= m;++ i){
        bu(i+m*n,ed,1);
    }
    for(i = 1;i <= n*m ;++ i){
        for(j = 1;j <= m ;++ j){
            if(mid >= ti[i][j]){
                bu(i,j + n*m,1);
            }
        }
    }
}

double maxflow(){
    double ans=0;
    while(bfs()){
        ans+=dfs(st,inf);
    }
    return ans;
}

void so(){
    double l,r,mid;
    l = 0.0,r=2000000.0;
    while(r - l >= eps){
        mid = (r + l) / 2.0;
        cnt=0;
        memset(head,-1,sizeof(head));
        creat(mid);
        if(maxflow() == m){
            r =  mid;
        }
        else
            l = mid;
    }
    printf("%.6lf\n",r);
}
int main(){
    int i,j,k;double s1,s2,sp;
    while(~scanf("%d%d%lf%lf%lf",&n,&m,&s1,&s2,&sp)){
        s1 /= 60.0;
        st = 0,ed = n * m + m + 1;
        for(i = 1;i <= m; ++ i){
            scanf("%d%d",&aim[i].a,&aim[i].b);
        }
        for(i = 1;i <= n;++ i){
            scanf("%d%d",&mis[i].a,&mis[i].b);
        }

        for(i = 1;i <= n;++ i){
            for(j = 1;j <= m;++ j){
                dis[i][j] = sqrt((mis[i].a-aim[j].a)*(mis[i].a-aim[j].a)+(mis[i].b-aim[j].b)*(mis[i].b-aim[j].b) );
            }
        }

        for(i = 1;i <= n;++ i){
            for(k = 1;k <= m ;++ k){
                for(j = 1;j <= m; ++j){
                    ti[(i-1)*m + k][j] = s1 * k +s2*(k-1) + dis[i][j] / sp;
                }
            }
        }
        so();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值