hdu 5988 Coding Contest【2016青島區域賽現場賽G】【費用流】
阿新 • • 發佈:2018-12-13
題意:
給你N個區域,M條路。接下來N行,每行bi,si,每一區域有bi個人,si個食物。食物是不動的,需要人沿著路去找食物,一人一個。
接下來M行,vi,ui,ci,pi代表vi和ui之間有一條路,最多可以走過ci個人,第一個走過去不會損壞路,之後走過去的人有pi的概率損壞路,問你如果都找到自己的食物的最小的損壞路的概率是多少
分析:
最小的損壞=1-最大的不損壞=1-(1-p1)^k*(1-p2)^k2....................
1.先建一個源點s和一個匯點t
2.之後將每一個點與s建一條費用為0,容量為bi的邊和t建一條費用為0,容量為si的邊
3.路徑是在路的兩個端點之間建一條容量為c-1,費用為-log(1-p)的邊(乘法換成加法,要換成log(1-p1)+log(1-p2)=log((1-p1)*(1-p2)),因為是用求最小費用的模板,但我們希望他們的和越大越好,所以要取反);同時在他們之間還要建一條容量為1,費用為0的點(因為第一次走不會損壞路)
程式碼:
#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; } /* 999999 4 4 2 0 0 3 3 0 0 3 1 2 5 0.5 3 2 5 0.5 1 4 5 0.5 3 4 5 0.5 4 2 0 3 3 0 0 3 3 0 1 2 5 0.5 3 4 5 0.5 3 2 0 2 1 1 2 0 1 2 2 0.3 2 3 2 0.2 3 3 0 2 1 1 2 0 1 2 2 0.3 2 3 2 0.3 1 3 2 0.3 3 2 1 1 2 0 0 2 1 2 1 0.3 2 3 2 0.7 2 1 4 0 0 4 1 2 4 0.3 */