AC日记——[SDOI2015]星际战争 洛谷 P3324

题目描述

3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战。

在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团的阵地,其中第i个巨型机器人的装甲值为Ai。当一个巨型机器人的装甲值减少到0或者以下时,这个巨型机器人就被摧毁了。

X军团有M个激光武器,其中第i个激光武器每秒可以削减一个巨型机器人Bi的装甲值。激光武器的攻击是连续的。

这种激光武器非常奇怪,一个激光武器只能攻击一些特定的敌人。Y军团看到自己的巨型机器人被X军团一个一个消灭,他们急需下达更多的指令。

为了这个目标,Y军团需要知道X军团最少需要用多长时间才能将Y军团的所有巨型机器人摧毁。但是他们不会计算这个问题,因此向你求助。

输入输出格式

输入格式:

第一行,两个整数,N、M。第二行,N个整数,A1、A2...AN。第三行,M个整数,B1、B2...BM。接下来的M行,每行N个整数,这些整数均为0或者1。这部分中的第i行的第j个整数为0表示第i个激光武器不可以攻击第j个巨型机器人,为1表示第i个激光武器可以攻击第j个巨型机器人。

输出格式:

一行,一个实数,表示X军团要摧毁Y军团的所有巨型机器人最少需要的时间。输出结果与标准答案的绝对误差不超过10-3即视为正确。

输入输出样例

输入样例#1:
2 2
3 10
4 6
0 1
1 1
输出样例#1:
1.300000

说明

【样例说明1】

战斗开始后的前0.5秒,激光武器1攻击2号巨型机器人,激光武器2攻击1号巨型机器人。1号巨型机器人被完全摧毁,2号巨型机器人还剩余8的装甲值;

接下来的0.8秒,激光武器1、2同时攻击2号巨型机器人。2号巨型机器人被完全摧毁。

对于全部的数据,1<=N, M<=50,1<=Ai<=105,1<=Bi<=1000,输入数据保证X军团一定能摧毁Y军团的所有巨型机器人

[spj]

思路:

  二分+最大流;

  轻松ac;

  二分时间,用最大流判断是否能达到装甲总值;

来,上代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define maxn 101
#define INF 9999999.99
#define EFlit 10000.0

using namespace std;

struct EdgeType {
    int v,e;
    
    double f;
};
struct EdgeType edge[maxn*maxn<<1];

int if_z,n,m,head[maxn<<2],s,t=(maxn<<2)-1;
int ai[maxn],bi[maxn],tota,totb,map[maxn][maxn];
int deep[maxn<<2],cnt;

double dai[maxn],dbi[maxn];

char Cget;

inline void in(int &now)
{
    now=0,if_z=1,Cget=getchar();
    while(Cget>'9'||Cget<'0')
    {
        if(Cget=='-') if_z=-1;
        Cget=getchar();
    }
    while(Cget>='0'&&Cget<='9')
    {
        now=now*10+Cget-'0';
        Cget=getchar();
    }
    now*=if_z;
    return ;
}

bool bfs()
{
    queue<int>que;
    memset(deep,-1,sizeof(deep));
    que.push(s);deep[s]=0;
    while(!que.empty())
    {
        int pos=que.front();que.pop();
        for(int i=head[pos];i;i=edge[i].e)
        {
            if(deep[edge[i].v]<0&&edge[i].f>0)
            {
                deep[edge[i].v]=deep[pos]+1;
                if(edge[i].v==t) return true;
                que.push(edge[i].v);
            }
        }
    }
    return false;
}

double flowing(int now,double flow)
{
    if(now==t||flow==0) return flow;
    double oldflow=0;
    for(int i=head[now];i;i=edge[i].e)
    {
        if(deep[edge[i].v]==deep[now]+1&&edge[i].f>0)
        {
            double pos=flowing(edge[i].v,min(flow,edge[i].f));
            if(pos>0)
            {
                flow-=pos;
                oldflow+=pos;
                edge[i].f-=pos;
                edge[i^1].f+=pos;
                if(flow==0) return oldflow;
            }
        }
    }
    if(oldflow==0) deep[now]=-1;
    return oldflow;
}

inline void edge_add(int u,int v,double f)
{
    edge[++cnt].v=v,edge[cnt].f=f,edge[cnt].e=head[u],head[u]=cnt;
    edge[++cnt].v=u,edge[cnt].f=0,edge[cnt].e=head[v],head[v]=cnt;
}

bool check(double ans_)
{
    cnt=1;
    memset(head,0,sizeof(head));
    for(int i=1;i<=m;i++) edge_add(s,i,dbi[i]*ans_);
    for(int i=1;i<=n;i++) edge_add(i+m,t,dai[i]);
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(map[i][j]) edge_add(i,j+m,INF);
        }
    }
    double pos=0;
    while(bfs()) pos+=flowing(s,INF);
    if(pos>=(double)tota-0.001) return true;
    else return false;
}

int main()
{
    in(n),in(m);
    for(int i=1;i<=n;i++)
    {
        in(ai[i]);
        tota+=ai[i];
        dai[i]=ai[i];
    }
    for(int i=1;i<=m;i++)
    {
        in(bi[i]);
        totb+=bi[i];
        dbi[i]=bi[i];
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++) in(map[i][j]);
    }
    double l=(double)tota/(double)totb,r=EFlit,mid,ans;
//    double l=0,r=EFlit,mid,ans;
    while(l<r)
    {
        mid=(l+r)/2.0;
        if(check(mid)) ans=mid,r=mid-0.0001;
        else l=mid+0.0001;
    }
    printf("%lf
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6637919.html