HDU 5988 Coding Contest(最小費用最大流)

Coding Contest

題意:nn個區域,每個區域有一些食物和人,mm條有向路徑,每條路徑有人數上限,第一個通過的人不會觸電,之後通過的人有p%p\%的概率觸電,求所有人都獲取到食物觸電的最小概率。

題解:轉換爲求不會觸電的最大概率。但是呢,我們在費用流裏都是通過相加得到的結果,所以有沒有將乘法變爲加法的方法呢?沒錯,就是loglog,取個log就變成了加法。對於uuvv,首先連一條費用爲00流量爲11的邊,再連一條費用爲log2(1p)-log_2(1-p)流量爲cap1cap-1的邊。最後令源點連向人多餘的點,食物多餘的點向匯點連邊。然後最後取得答案再轉換回來即可。

代碼

#include<bits/stdc++.h>
const int N = 21010, inf = 2e9;
using namespace std;
int n,m,s[200],b[200];
struct Edge{
    int to,nxt,cap,flow;
    double cost;
    Edge() {}
    Edge(int x,int y,int z,int p,double s) : to(x),nxt(y),cap(z),flow(p),cost(s) {}
}edge[N];
int head[200],pre[200],tot;
double dis[200];
bool vis[N];

void init() {
    tot = 0;
    memset(head,-1,sizeof head);
}

void addEdge(int u,int v,int cap,double cost) {
    edge[tot] = Edge(v,head[u],cap,0,cost);
    head[u] = tot++;
    edge[tot] = Edge(u,head[v],0,0,-cost);
    head[v] = tot++;
}

bool spfa(int s,int t) {
    queue<int> q;
    memset(vis, 0, sizeof vis);
    memset(pre, -1, sizeof pre);
    for(int i = s; i <= t; ++i) dis[i] = inf;
    dis[s] = 0;
    vis[s] = 1;
    q.push(s);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = edge[i].nxt) {
            int v = edge[i].to;
            if(edge[i].cap > edge[i].flow && dis[v] - dis[u] - edge[i].cost > 1e-8) {
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if(!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t] == -1) return 0; 
    return 1;
}

void mcmf(int s,int t,double &cost) {
    int flow = 0;
    while(spfa(s,t)) {
        int min1 = inf;
        for(int i = pre[t]; ~i; i = pre[edge[i^1].to]) {
            if(min1 > edge[i].cap - edge[i].flow) 
                min1 = edge[i].cap - edge[i].flow;
        }
        for(int i = pre[t]; ~i; i = pre[edge[i^1].to]) {
            edge[i].flow += min1;
            edge[i ^ 1].flow -= min1;
            cost += edge[i].cost * min1;
        }
        flow += min1;
    }
}

int main()
{ 
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    int T,c,u,v; double p;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        init();
        for(int i = 1; i <= n; ++i){
            scanf("%d%d",&s[i],&b[i]);
            if(s[i] > b[i]) {
                addEdge(0,i,s[i] - b[i],0);
            }else{addEdge(i,n + 1,b[i] - s[i],0);
            }
        }
        for(int i = 1; i <= m; ++i){
            scanf("%d%d%d%lf",&u,&v,&c,&p);
            addEdge(u,v,c-1,-log2(1.0-p));
            addEdge(u,v,1,0);
        }
        double cost = 0;
        mcmf(0,n + 1,cost);
        printf("%.2f\n",1.0 - pow(2,-cost));
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章