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即视为正确。
输入输出样例
2 2 3 10 4 6 0 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\n",ans); return 0; }