BZOJ3993 星際戰爭 題解(二分+最大流)
阿新 • • 發佈:2019-02-08
星際戰爭
【問題描述】
3333年,在銀河系的某星球上,X軍團和Y軍團正在激烈地作戰。在戰鬥的某一階段,Y軍團一共派遣了N個巨型機器人進攻X軍團的陣地,其中第i個巨型機器人的裝甲值為Ai。當一個巨型機器人的裝甲值減少到0或者以下時,這個巨型機器人就被摧毀了。X軍團有M個鐳射武器,其中第i個鐳射武器每秒可以削減一個巨型機器人Bi的裝甲值。鐳射武器的攻擊是連續的。這種鐳射武器非常奇怪,一個鐳射武器只能攻擊一些特定的敵人。Y軍團看到自己的巨型機器人被X軍團一個一個消滅,他們急需下達更多的指令。為了這個目標,Y軍團需要知道X軍團最少需要用多長時間才能將Y軍團的所有巨型機器人摧毀。但是他們不會計算這個問題,因此向你求助。
【資料規模和約定】
對於30%的資料,1<=N, M<=5;
對於全部的資料,1<=N,M<=50,1<=Ai<=105,1<=Bi<=1000,輸入資料保證X軍團一定能摧毀Y軍團的所有巨型機器人。
建立一個網路,源點S,匯點T。S連到所有的鐳射節點,鐳射節點連到能攻擊到的巨人節點,所有巨人節點連到T。二分時間t,將所有S到鐳射節點的最大流量設定為輸出的攻擊總量Bi*t,巨人節點和T之間的流量設定為Ai。
對這個圖跑最大流,如果最大流等於所有裝甲值之和,說明能在規定時間內能打掉所有巨人,更新上界。否則更新下界。
注意精度問題,float的精度不夠。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<vector> #include<queue> #include<cmath> #define INF 2333333 using namespace std; int cnt=0; const double eps=1e-6; vector<int> tab[4000]; int n,m; int dis[4000]; int cur[4000]; double a[55],b[55]; int S,T; double sum; struct edge { int u,v; double cap; edge(int u_,int v_,double cap_){u=u_;v=v_;cap=cap_;} edge(){} }eg[8000]; void addedge(int u,int v,double c) { eg[cnt]=edge(u,v,c); tab[u].push_back(cnt++); eg[cnt]=edge(v,u,0); tab[v].push_back(cnt++); } void modify(double t) { int i=0; for(int j=1;j<=n;i+=2,++j) { eg[i].cap=a[j]; eg[i^1].cap=0.0; } for(int j=1;j<=m;i+=2,++j) { eg[i].cap=t*b[j]; eg[i^1].cap=0.0; } for(;i<cnt;++i) { if(i&1)eg[i].cap=0.0; else eg[i].cap=INF; } } queue<int> q; bool bfs() { q.push(S); for(int i=S;i<=T;++i) dis[i]=INF; dis[S]=0; while(!q.empty()) { int now = q.front(); q.pop(); int sz=tab[now].size(); for(int i=0;i<sz;++i) { edge& e=eg[tab[now][i]]; if(dis[e.v]>dis[now]+1&&e.cap>eps) { dis[e.v]=dis[now]+1; q.push(e.v); } } } return dis[T]<INF; } double dfs(int now,double flow) { if(now==T)return flow; int sz=tab[now].size(); for(int& i=cur[now];i<sz;++i) { edge& e=eg[tab[now][i]]; if(dis[now]+1==dis[e.v]&&e.cap>eps) { double f=dfs(e.v,(double)min(flow,e.cap)); if(f>eps) { e.cap-=f; eg[tab[now][i]^1].cap+=f; return f; } } } return 0; } double dinic() { double ans=0,flow=0; while(bfs()) { memset(cur,0,sizeof(cur)); while((flow=dfs(S,INF))>eps) ans+=flow; } return ans; } bool can(double t) { modify(t); double flow=dinic(); return fabs(flow-sum)<eps; } double bsearch(double l,double r) { if(r-l<eps)return (l+r)/2.0; double mid = (l+r)/2.0; if(can(mid))return bsearch(l,mid); else return bsearch(mid,r); } int main() { //freopen("war.in","r",stdin); //freopen("war.out","w",stdout); scanf("%d%d",&n,&m); S=1;T=n+m+2; for(int i=1;i<=n;++i) { scanf("%lf",&a[i]); sum+=a[i]; addedge(m+i+1,T,a[i]); } for(int i=1;i<=m;++i) { scanf("%lf",&b[i]); addedge(S,i+1,0.0); } for(int i=1;i<=m;++i) { for(int j=1;j<=n;++j) { int c; scanf("%d",&c); if(c==1)addedge(i+1,m+j+1,INF); } } printf("%.6lf\n",bsearch(0.0,100010.0)); return 0; }