HDU - 5988 2016 QingDao ICPC G (费用流)

题目:https://vjudge.net/problem/HDU-5988

题意:一个网络流的图,有n个点,从1~n,然后m条边,每个点有两个值,一个是人的数量一个是饭的数量。每条边有容量,还有走上去可能踩断电线的几率。问让所有人吃到饭的前提下断电线的最小概率是多少。 

分析:使用log把乘法变加法,先建容量为1,费用为0的边,之后建正常的边,以0,n+1为源点和汇点跑费用流即可

代码:
 

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const double eps = 1e-9;
const int N = 1000 + 7 ,  M = 100000 + 7;
int head[N],nxt[M],to[M],from[M],cap[M];
double cost[M];
int d[N],pree[N],inq[N];
double dis[N];
int n,m,nEdge;
void AddEdge(int u,int v,int c,double co){
    nxt[nEdge] = head[u];
    to[nEdge] = v;
    from[nEdge] = u;
    cap[nEdge] = c;
    cost[nEdge] = co;
    head[u] = nEdge++;
}
double MIncostMaxFlow(int s,int t){
    int flow = 0;
    double res = 0;
    while(1){
        memset(dis,100,sizeof dis);
        memset(inq,0,sizeof inq);
        memset(d,0,sizeof d);
        dis[s] = 0;
        inq[s] = 1;
        pree[s] = 0;
        d[s] = inf;
        queue<int>q;
        q.push(s);
        while(!q.empty()){
            int u = q.front();q.pop();
            inq[u] = 0;
            for(int e = head[u];~e;e=nxt[e]){
                int v = to[e];
                if(cap[e]&&dis[v]>dis[u]+cost[e]+eps){
                    dis[v] = dis[u]+cost[e];
                    pree[v] = e;
                    d[v] = min(d[u],cap[e]);
                    if(!inq[v]){
                        q.push(v);
                        inq[v] = 1;
                    }
                }
            }
        }
        if(!d[t]) break;
        flow+=d[t];
        res+=d[t]*dis[t];
        for(int u=t;u!=s;u=from[pree[u]]){
            cap[pree[u]]-=d[t];
            cap[pree[u]^1]+=d[t];
        }
    }
    //cout<<res<<endl;
    return res;
}
int main(){
    freopen("i.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        memset(head,-1,sizeof head);
        nEdge = 0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            int x = a-b;
            if(x>0){
                AddEdge(0,i,x,0);
                AddEdge(i,0,0,0);
            }
            if(x<0){
                AddEdge(i,n+1,-x,0);
                AddEdge(n+1,i,0,0);
            }
        }
        for(int i=1;i<=m;i++){
            int u,v,c;
            double co;
            scanf("%d%d%d%lf",&u,&v,&c,&co);
            if(c>0){
                AddEdge(u,v,1,0);
                AddEdge(v,u,0,0);
            }
            if(c-1>0){
                AddEdge(u,v,c-1,-log(1.0-co));
                AddEdge(v,u,0,log(1.0-co));
            }
        }
        printf("%.2f\n",1-exp(-MIncostMaxFlow(0,n+1)));
    }
}

猜你喜欢

转载自blog.csdn.net/Insist_77/article/details/82933436