【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 23 10
4 6
0 1
1 1
Sample Output
1.300000HINT
【样例说明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); }
相关文章推荐
- postgreSQl导数据
- 秒杀系统的架构设计
- 配置管理1——设计模式综合项目实战 x-gen代码生成器
- 理解Netty中的Zero-copy
- android 滑动事件冲突解决
- 根据日期查询数据库中的信息
- 浅谈android开发中的MVP模式
- 使用动态规划求解最长公共子序列(LCS)
- 用java生成html文件
- 什么是BGP协议?
- 深入理解abstract class和interface(转)
- 在PHP中使用协程实现多任务调度
- C Runtime Library 的来历
- Java Web中乱码问题的总结
- Java 实例 - 队列(Queue)用法
- WebSocket的JavaScript例子
- Intellij设置依赖项目
- 网址
- [Clean Code] Chapter 8: 第三方API的使用!
- 形态学图像处理