HDU 5988.Coding Contest 最小費用最大流

Coding Contest

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1751    Accepted Submission(s): 374


php

Problem Description
A coding contest will be held in this university, in a huge playground. The whole playground would be divided into N blocks, and there would be M directed paths linking these blocks. The i-th path goes from the  ui-th block to the vi-th block. Your task is to solve the lunch issue. According to the arrangement, there are sicompetitors in the i-th block. Limited to the size of table, bi bags of lunch including breads, sausages and milk would be put in the i-th block. As a result, some competitors need to move to another block to access lunch. However, the playground is temporary, as a result there would be so many wires on the path.
For the i-th path, the wires have been stabilized at first and the first competitor who walker through it would not break the wires. Since then, however, when a person go through the i - th path, there is a chance of pi to touch
the wires and affect the whole networks. Moreover, to protect these wires, no more than ci competitors are allowed to walk through the i-th path.
Now you need to find a way for all competitors to get their lunch, and minimize the possibility of network crashing.
 

 

Input
The first line of input contains an integer t which is the number of test cases. Then t test cases follow.
For each test case, the first line consists of two integers N (N ≤ 100) and M (M ≤ 5000). Each of the next N lines contains two integers si and  bi (si , bi ≤ 200).
Each of the next M lines contains three integers ui , vi and ci(ci ≤ 100) and a float-point number pi(0 < pi < 1).
It is guaranteed that there is at least one way to let every competitor has lunch.
 

 

Output
For each turn of each case, output the minimum possibility that the networks would break down. Round it to 2 digits.
 

 

Sample Input
1
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
 

 

Sample Output
0.50
 

 

Source
 
 
 
題意:有n個區域,每一個區域有一些人數si和食物bi,區域之間有m條定向路徑,每條路徑有人數經過上限ci。路徑之間鋪了電線,每當有人經過路徑時有pi的機率會觸碰到電線,可是第一個經過的人必定不會觸碰到電線。求每一個人都經過路徑獲取到食物後觸碰到電線的最小几率。
思路:首先每一個區域的一些人都直接獲取本身區域的食物,若是人過量,源點連接本區域,容量是過量的人數,費用是0;若是食物過量,本區域鏈接匯點,容量是過量的食物,費用是0。剩下的人經過路徑到其餘區域獲取食物,m條路徑之間創建邊,首先是必定不會觸碰,容量是1,花費爲0,;接下來的纔是容量爲ci-1的邊,而且還擁有一個費用,這就是一個最小費用最大流的問題,可是這個費用怎麼轉換呢?把每一個機率取log(1-pi),而且取負數-log(1-pi)。這樣的話最小花費(-log(x1))+(-log(x2))+(-log(x3))+....=-(log(x1)+log(x2)+log(x3)+...)=-log(x1*x2*x3...)。最後最小費用ans取負數再做爲e的指數,即exp(-ans)是最大乘積。
 
代碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<double,int> P;
#define PI acos(-1.0)
const int maxn=200,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=1e18+7;
const double eps=0.000001;
struct edge
{
    int from,to;
    int cap;
    double cost;
    int rev;
};
int NN;
vector<edge>G[maxn];
double h[maxn];
///頂點的勢,取h(u)=(s到u的最短距離),邊e=(u,v)的長度變成d`(e)=d(e)+h(u)-h(v)>=0
double dist[maxn];
int prevv[maxn],preve[maxn];///前驅結點和對應的邊
void addedge(int u,int v,int cap,double cost)
{
    edge e;
    e.from=u,e.to=v,e.cap=cap,e.cost=cost,e.rev=G[v].size();
    G[u].push_back(e);
    e.from=v,e.to=u,e.cap=0,e.cost=-cost,e.rev=G[u].size()-1;
    G[v].push_back(e);
}
double min_cost_flow(int s,int t,int f)
{
    double res=0.0;
    fill(h,h+NN,0.0);
    while(f>0)
    {
        priority_queue<P,vector<P>,greater<P> >q;
        fill(dist,dist+NN,inf);
        dist[s]=0.0;
        q.push(P(dist[s],s));
        while(!q.empty())
        {
            P p=q.top();
            q.pop();
            int u=p.second;
            if(dist[u]<p.first) continue;
            for(int i=0; i<G[u].size(); i++)
            {
                edge e=G[u][i];
                if(e.cap>0&&dist[e.to]-(dist[u]+e.cost+h[u]-h[e.to])>=eps)
                {
                    dist[e.to]=dist[u]+e.cost+h[u]-h[e.to];
                    prevv[e.to]=u;
                    preve[e.to]=i;
                    q.push(P(dist[e.to],e.to));
                }
            }
        }
        if(fabs(dist[t]-inf)<=eps) return res;
        for(int i=0; i<NN; i++) h[i]+=dist[i];
        int d=f;
        for(int i=t; i!=s; i=prevv[i])
            d=min(d,G[prevv[i]][preve[i]].cap);
        f-=d;
        res+=d*h[t];
        //cout<<d<<" "<<h[t]<<" "<<d*h[t]<<endl;
        for(int i=t; i!=s; i=prevv[i])
        {
            //cout<<i<<" ";
            edge &e=G[prevv[i]][preve[i]];
            e.cap-=d;
            G[i][e.rev].cap+=d;
        }
        //cout<<s<<endl;
    }
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int s=0,t=n+1,f;
        NN=t+1;
        for(int i=1; i<=n; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            int x=min(a,b);
            a-=x,b-=x;
            if(a>0) addedge(s,i,a,0);
            else if(b>0) addedge(i,t,b,0);
        }
        for(int i=1; i<=m; i++)
        {
            int u,v,cap;
            double cost;
            scanf("%d%d%d%lf",&u,&v,&cap,&cost);
            if(cap>0) addedge(u,v,1,0);
            if(cap-1>0) addedge(u,v,cap-1,-1*log(1.0-cost));
        }
        double sum=min_cost_flow(s,t,inf);
        printf("%.2f\n",1.0-exp(-1.0*sum));
        for(int i=0; i<NN; i++) G[i].clear();
    }
    return 0;
}
最小費用最大流
相關文章
相關標籤/搜索