[2019.1.17]BZOJ3993 [SDOI2015]星際戰爭
阿新 • • 發佈:2019-03-17
流量 str print ace while ron 問題 include mem 的邊,即它在\(M\)時間內可以造成的總傷害。
容易想到一個網絡流模型,就是將武器作為節點放在左邊,機器作為節點放在右邊,一個武器可以攻擊一個機器,就在這個武器和這個機器之間連容量為\(inf\)的邊,因為武器可以攻擊機器任意多的傷害。
那麽如何建立其他邊呢?
由於最小時間不好求,我們考慮二分答案\(Time\)(註意這是一個實數),將問題轉化為詢問可行性,設當前答案區間的中點為\(M\)。
然後我們建立匯點\(t\),機器\(i\)向\(t\)連一條容量為\(A_i\)的邊,這條邊的流量變為0表示這臺機器受到了\(A_i\)的傷害,即被摧毀了;
接下來我們建立源點\(s\),\(s\)向每個武器\(i\)連一條容量為\(B_i\times M\)
我們只需檢查這個網絡的最大流是否等於\(\sum_{i=1}^nA_i\)即可。
由於需要進行實數比較,記得定義精度。此題建議精度為\(10^{-9}\)到\(10^{-8}\)之間,\(10^{-10}\)太小了會WA掉。
code:
#include<bits/stdc++.h> #define REV(x) ((x&1)?x+1:x-1) using namespace std; const double INF=1e9; const double _=1e-9; struct edge{ int t,nxt; double w; }e[5210]; int n,m,a[55],b[55],ch[55][55],t,be[110],cnt,sum,dep[110],vis[110]; double l,r,mid,fl[110]; queue<int>q; void add(int x,int y,double v){ e[++cnt].t=y,e[cnt].w=v,e[cnt].nxt=be[x],be[x]=cnt; } bool eq(double x,double y){ return abs(x-y)<=_; } void Build(double tim){ cnt=0,memset(be,0,sizeof(be)); for(int i=1;i<=n;i++)add(m+i,n+m+1,a[i]),add(n+m+1,m+i,0); for(int i=1;i<=m;i++)add(0,i,b[i]*tim),add(i,0,0.0); for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)ch[i][j]?add(i,m+j,INF),add(m+j,i,0),0:0; } bool Getd(int x){ memset(dep,0,sizeof(dep)); q.push(x),dep[x]=1; int tg=0; while(!q.empty()){ t=q.front(),q.pop(),tg++; for(int i=be[t];i;i=e[i].nxt)(!eq(e[i].w,0)&&!dep[e[i].t])?q.push(e[i].t),dep[e[i].t]=dep[t]+1:0; } return dep[n+m+1]; } void Upd(int ei,double fl){ e[ei].w-=fl,e[REV(ei)].w+=fl; } double dfs(int x,double nf){ if(x==n+m+1)return nf; vis[x]=1; double af,tf=0; for(int i=be[x];!eq(nf,0.0)&&i;i=e[i].nxt){ (!eq(e[i].w,0.0)&&!vis[e[i].t]&&dep[e[i].t]==dep[x]+1)?af=dfs(e[i].t,min(nf,e[i].w)),Upd(i,af),nf-=af,tf+=af:0; } return vis[x]=0,tf; } double Dinic(){ double tot=0; while(Getd(0))tot+=dfs(0,INF); return tot; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",&a[i]),sum+=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",&ch[i][j]); Build(0); Getd(0); r=sum; for(int fr=1;fr<=200;++fr){ mid=(l+r)/2.0; Build(mid); eq(Dinic(),sum)?r=mid:l=mid; } printf("%.10lf",l); return 0; }
[2019.1.17]BZOJ3993 [SDOI2015]星際戰爭