Coding Contest

来源:互联网 发布:笑傲江湖 知乎 编辑:程序博客网 时间:2024/06/18 05:58

这里写图片描述
这里写图片描述

给定n个点,m条有向边,每个点有学生和食物,要求所有学生通过有向边获得食物(保证有解)。问题是现在每条边都有线路,第一个学生经过的时候不会碰到,之后每个经过这条线路的学生都有pi的几率会碰到线路导致网络崩溃,要求满足条件的同事使得网络崩溃率最低。

首先要求网络崩溃率最简单就是1-不崩溃的几率。建立费用流,首先考虑如何收费。因为费用流权值只能相加,所以考虑把所有的概率取上log之后变成每条边的费用。其次由于是最小费用,我们求不被破坏的概率应该最大,所以每个权值取负值。然后建图,从源点到每个有学生的点建立一条容量为学生数量的边,每个有食物的点到汇点建一条容量为食物的边,费用都为0。对于有向边,考虑拆边,分别是容量为1,费用为0的边(第一个经过学生不破坏的概率是1,取log就是0,正负都一样),随后建容量为cap-1,费用为 -log(1.0-cost)的边,跑费用流就好了。

#include <bits/stdc++.h>using namespace std;const int MAXN = 500;const int MAXM = 50000;const int INF = 0x3f3f3f3f;const double eps = 1e-6;struct Edge {    int to, next, cap, flow;    double cost;} edge[MAXM];int head[MAXN],tol;int pre[MAXN];double dis[MAXN];bool vis[MAXN];int N, T;//节点总个数,节点编号从0~N-1void init(int n) {    N = n;    tol = 0;    memset(head, -1, sizeof(head));}void addedge(int u,int v,int cap,double cost) {    edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u];    head[u] = tol++;    edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++;}bool spfa(int s,int t) {    queue<int>q;    for(int i = 0;i < N;i++) {        dis[i] = INF;        vis[i] = false;        pre[i] = -1;    }    dis[s] = 0;    vis[s] = true;    q.push(s);    while(!q.empty()) {        int u = q.front();        q.pop();        vis[u] = false;        for(int i = head[u]; i != -1;i = edge[i].next) {            int v = edge[i].to;            if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost+eps ) {                dis[v] = dis[u] + edge[i].cost;                pre[v] = i;                if(!vis[v]) {                    vis[v] = true;                    q.push(v);                }            }        }    }    if(pre[t] == -1)return false;    else return true;}//返回的是最大流,cost存的是最小费用int minCostMaxflow(int s,int t,double &cost) {    int flow = 0;    cost = 0;    while(spfa(s,t)) {        int Min = INF;        for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) {            if(Min > edge[i].cap - edge[i].flow)            Min = edge[i].cap - edge[i].flow;        }        for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) {            edge[i].flow += Min;            edge[i^1].flow -= Min;            cost += edge[i].cost * Min;        }        flow += Min;    }    return flow;}int n, m, x, y, t, cap;double cost, ans;int main() {    freopen("input.txt","r",stdin);    scanf("%d", &T);    while (T--) {        scanf("%d %d", &n, &m);        init(n+2);        for (int i = 1; i <= n; i++) {            scanf("%d %d", &x, &y);            t = min(x, y);            x -= t, y -= t;            if (x) addedge(0, i, x, 0);            if (y) addedge(i, n+1, y, 0);        }        for (int i = 1; i <= m; i++) {            scanf("%d %d %d %lf", &x, &y, &cap, &cost);            if (cap > 0) addedge(x, y, 1, 0);            if (cap-1 > 0) addedge(x, y, cap-1, -log(1.0-cost));        }        ans = 0;        minCostMaxflow(0, n+1, ans);        printf("%.2lf\n", 1.0-exp(-ans));    }}
原创粉丝点击