2016年ACM/ICPC青島賽區 G題(費用流)
阿新 • • 發佈:2018-11-11
題意:
n(n<=200)個地點,m(m<=5000)座橋。
給出每個地點的 人數 和 食物數量。
再給出m行,每行u,v表示哪兩個被一座橋相連,為了保證橋的安全,最多隻允許通過v人,第一個人通過時橋不會塌,後面的人每通過一個,橋就會有p的概率塌掉。求怎樣安排,使每個人都有一份食物,且有橋塌的概率最低,輸出橋塌的概率。
思路:典型費用流。對於人數多的地點,多了幾個人源點就向它連邊容量為多的人數,費用為0。
對於食物多的地點,多了幾份食物它就向匯點連邊,容量為多的食物數,費用為0。
求概率,只需要取log,再跑完最小費用最大流的時候再取回exp(cost)就行了。
注意求的是最小橋塌概率,我們用橋不塌的概率計算費用最後用1減。
但是又要求最短路,於是取-log(1-p),最後再取exp(-cost) ,答案就是用1減去它。
程式碼:
#include<bits/stdc++.h> using namespace std; const int maxn = 205; #define inf 1e9 #define eps 1e-8 struct Edge { int from,to,cap,flow; double cost; Edge(){} Edge(int f,int t,int c,int fl,double co):from(f),to(t),cap(c),flow(fl),cost(co){} }; struct MCMF { int n,m,s,t; vector<Edge>edges; vector<int>g[maxn]; bool inq[maxn]; double d[maxn]; int p[maxn]; int a[maxn]; void init(int n,int s,int t) { this->n=n; this->s=s; this->t=t; edges.clear(); for(int i = 0;i<=n;i++)g[i].clear(); } void add(int from,int to,int cap,double cost) { edges.push_back(Edge(from,to,cap,0,cost)); edges.push_back(Edge(to,from,0,0,-cost)); m=edges.size(); g[from].push_back(m-2); g[to].push_back(m-1); } bool BellmanFord(int &flow,double &cost) { for(int i = 0;i<=n;i++)d[i]=inf; memset(inq,0,sizeof(inq)); d[s]=0,a[s]=inf,inq[s]=1,p[s]=0; queue<int>q; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); inq[u]=0; for(int i = 0;i<g[u].size();i++) { Edge &e = edges[g[u][i]]; if(e.cap>e.flow&&d[e.to]>d[u]+e.cost+eps) { d[e.to]=d[u]+e.cost; p[e.to]=g[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]) { q.push(e.to); inq[e.to]=1; } } } } if(d[t]==inf)return false; flow+=a[t]; cost+=a[t]*d[t]; int u = t; while(u!=s) { edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; u=edges[p[u]].from; } return true; } double work(int &flow,double &cost) { flow=0,cost=0; while(BellmanFord(flow,cost)); return cost; } }mm; int a[maxn],b[maxn]; int main(){ int Tc,cas=1,S,T,n,m; double cst; // scanf("%d",&Tc); cin>>Tc; { while(Tc--) { //scanf("%d%d",&n,&m); cin>>n>>m; S=0;T=n+1; mm.init(n+1,S,T); for(int i=1;i<=n;i++) { cin>>a[i]>>b[i]; //scanf("%d %d",&a[i],&b[i]); int k=min(a[i],b[i]); a[i]-=k;b[i]-=k; if(a[i]) mm.add(S,i,a[i],0); if(b[i]) mm.add(i,T,b[i],0); } for(int i=1;i<=m;i++) { int x,y,z; double p; //scanf("%d%d%d%lf",&x,&y,&z,&p); cin>>x>>y>>z>>p; p=-log(1-p); if(z>0) mm.add(x,y,1,0); if(z>1) mm.add(x,y,z-1,p); } int mf; mm.work(mf,cst); cst=exp(-cst); cst=1.00000-cst; cout<<fixed<<setprecision(2)<<cst<<endl; } } return 0; }