【BZOJ3993】星际战争(网络流,二分答案)

【BZOJ3993】星际战争(网络流,二分答案)

题面

Description

3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战。在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团的阵地,其中第i个巨型机器人的装甲值为Ai。当一个巨型机器人的装甲值减少到0或者以下时,这个巨型机器人就被摧毁了。X军团有M个激光武器,其中第i个激光武器每秒可以削减一个巨型机器人Bi的装甲值。激光武器的攻击是连续的。这种激光武器非常奇怪,一个激光武器只能攻击一些特定的敌人。Y军团看到自己的巨型机器人被X军团一个一个消灭,他们急需下达更多的指令。为了这个目标,Y军团需要知道X军团最少需要用多长时间才能将Y军团的所有巨型机器人摧毁。但是他们不会计算这个问题,因此向你求助。

Input

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

Output

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

Sample Input

2 2

3 10

4 6

0 1

1 1

Sample Output

1.300000

HINT

【样例说明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军团的所有巨型机器人

题解

每个激光武器造成的伤害是一定的
只是分配的问题
于是,在固定的时间里,产生的总伤害是一定的
因此,二分一个时间
检查在这个时间内产生的伤害是否等于机器人的总血量即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define INF 1e9
#define MAXL 50000
#define MAX 500
inline int read()
{
	int x=0,t=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=-1,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*t;
}
int A[MAX],B[MAX];
int g[MAX][MAX];
struct Line
{
    int v,next;
	double w;
}e[MAXL];
int h[MAX],cnt;
int ans,S,T,n,m;
inline void Add(int u,int v,double w)
{
    e[cnt]=(Line){v,h[u],w};
    h[u]=cnt++;
    e[cnt]=(Line){u,h[v],0};
    h[v]=cnt++;
}
int level[MAX];
int cur[MAX];
bool BFS()
{
    memset(level,0,sizeof(level));
    level[S]=1;
    queue<int> Q;
    Q.push(S);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int i=h[u];i!=-1;i=e[i].next)
        {
            int v=e[i].v;
            if(e[i].w&&!level[v])
                level[v]=level[u]+1,Q.push(v);
        }
    }
    return level[T];
}
double DFS(int u,double flow)
{
    if(flow==0||u==T)return flow;
    double ret=0;
    for(int &i=cur[u];i!=-1;i=e[i].next)
    {
        int v=e[i].v;
        if(e[i].w&&level[v]==level[u]+1)
        {
            double dd=DFS(v,min(flow,e[i].w));
            flow-=dd;ret+=dd;
            e[i].w-=dd;e[i^1].w+=dd;
        }
    }
    return ret;
}
double Dinic()
{
    double ret=0;
    while(BFS())
    {
        for(int i=S;i<=T;++i)cur[i]=h[i];
        ret+=DFS(S,INF);
    }
    return ret;
}
void Build(double tt)
{
	memset(h,-1,sizeof(h));
	cnt=0;
	for(int i=1;i<=m;++i)Add(S,i,tt*B[i]);
	for(int i=1;i<=n;++i)Add(i+m,T,A[i]);
	for(int i=1;i<=m;++i)
		for(int j=1;j<=n;++j)
			if(g[i][j])
				Add(i,j+m,1e9);
}
int main()
{
	n=read();m=read();
	S=0;T=n+m+1;
	double sum=0;
	for(int i=1;i<=n;++i)sum+=A[i]=read();
	for(int i=1;i<=m;++i)B[i]=read();
	for(int i=1;i<=m;++i)
		for(int j=1;j<=n;++j)
			g[i][j]=read();
	double l=0,r=1e6;
	while(r-l>1e-5)
	{
		double mid=(l+r)/2;
		Build(mid);
		if(Dinic()>=sum)r=mid;
		else l=mid;
	}
	printf("%.6lf
",l);
	return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8136737.html