您的位置:首页 > 其它

【bzoj3993】【SDOI2015】【二分法+最大流】

2016-04-11 16:58 183 查看

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军团的所有巨型机器人
题解:
          二分+最大流验证即可。
          为了避免精度误差可以先乘上100000
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200
#define M 5000
#define inf 2100000000000000ll
#define P 100000
using namespace std;
int T,a
,b
,point
,next[M<<1],n,m,map[60][60];
int cur
,dis
,gap
,pre
,cnt(1);
double ans;
struct use{
int st,en;
long long v;
}e[M<<1];
void add(int x,int y,long long v){
//  cout<<x<<' '<<y<<' '<<v<<endl;
next[++cnt]=point[x];point[x]=cnt;
e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
next[++cnt]=point[y];point[y]=cnt;
e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;
}
long long isap(){
int i,u,f,s;
long long ans(0),mn;
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
gap[0]=T;u=1;
for (i=1;i<=T;i++) cur[i]=point[i];
while (dis[1]<T){
f=false;
for (i=cur[u];i;i=next[i])
if (dis[e[i].en]+1==dis[u]&&e[i].v){cur[u]=i;f=1;break;}
if (f){
pre[u=e[i].en]=i;
if (u==T){
mn=inf;
for (i=T;i!=1;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);
ans+=mn;
for (i=T;i!=1;i=e[pre[i]].st) e[pre[i]].v-=mn,e[pre[i]^1].v+=mn;
u=1;
}
}
else{
gap[dis[u]]--;if (!gap[dis[u]]) return ans;
for (s=T,i=point[u];i;i=next[i])if (e[i].v) s=min(s,dis[e[i].en]);
gap[dis[u]=s+1]++;cur[u]=point[u];if (u!=1) u=e[pre[u]].st;
}
}
return ans;
}
bool check(long long x){
memset(point,0,sizeof(point));
memset(next,0,sizeof(next));
cnt=1;long long sum(0);
for (int i=1;i<=m;i++)
add(1,i+1,(long long)b[i]*x);
for (int i=1;i<=n;i++){
add(i+m+1,T,(long long)a[i]*(long long)P);
sum+=(long long)a[i]*(long long)P;
}
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
if (map[i][j]) add(i+1,j+m+1,inf);
if (isap()==sum) return true;
else return false;
}
int main(){
scanf("%d%d",&n,&m);T=n+m+2;
for (int i=1;i<=n;i++)  scanf("%d",&a[i]);
for (int i=1;i<=m;i++) scanf("%d",&b[i]);
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
long long l=0,r=(long long)50000*(long long)P;
while (l<=r){
long long mid=(l+r)>>1;
if (check(mid)) r=mid-1;
else l=mid+1;
}
ans=l*1.0/P;
printf("%.6f",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: