HDU 5988 最小费用流

链接:

http://acm.split.hdu.edu.cn/showproblem.php?pid=5988

题意:

n个点,每个点有a个人和b包饭,m条边,第一次经过这条边没有问题,以后每一个经过的有p概率出问题

每条边有限制,问使得所有人都有饭吃且出问题的概率最小

题解:

无向图的费用流

把相乘的取下对数变成相加的就可以用最小费用流了

代码:

 30 #include <iomanip>
 31 const double eps = 1e-8;
 32 const int MAXM = 1e5 + 7;
 33 
 34 struct node{
 35     int to, next, cap;
 36     double cost;
 37 }edge[MAXM];
 38 int head[MAXN];
 39 int pre[MAXN];
 40 int vis[MAXN];
 41 double dist[MAXN];
 42 int n, m, tot;
 43 
 44 void init() {
 45     memset(head, -1, sizeof(head));
 46     tot = 0;
 47 }
 48 
 49 void add_edge(int u, int v, int cap, double  cost) {
 50     edge[tot].to = v;
 51     edge[tot].cap = cap;
 52     edge[tot].cost = cost;
 53     edge[tot].next = head[u];
 54     head[u] = tot++;
 55     edge[tot].to = u;
 56     edge[tot].cap = 0;
 57     edge[tot].cost = -cost;
 58     edge[tot].next = head[v];
 59     head[v] = tot++;
 60 }
 61 
 62 double mcf(int s, int t, int f) {
 63     double res = 0;
 64     while (f > 0) {
 65         rep(i, 0, n + 2) {
 66             dist[i] = 1e18;
 67             vis[i] = 0;
 68             pre[i] = -1;
 69         }
 70         queue<int> q;
 71         q.push(s);
 72         dist[s] = 0;
 73         vis[s] = 1;
 74         while (!q.empty()) {
 75             int u = q.front(); q.pop();
 76             vis[u] = 0;
 77             for (int i = head[u]; i != -1; i = edge[i].next) {
 78                 int v = edge[i].to;
 79                 if (edge[i].cap > 0 && 
 80                     dist[v] > dist[u] + edge[i].cost + eps){
 81                     dist[v] = dist[u] + edge[i].cost;
 82                     pre[v] = i;
 83                     if (!vis[v]) {
 84                         vis[v] = 1;
 85                         q.push(v);
 86                     }
 87                 }
 88             }
 89         }
 90         if (dist[t] == 1e18) return -1;
 91         int d = f;
 92         for (int v = pre[t]; v != -1; v = pre[edge[v ^ 1].to])
 93             d = min(d, edge[v].cap);
 94         f -= d;
 95         res += d * dist[t];
 96         for (int v = pre[t]; v != -1; v = pre[edge[v ^ 1].to]) {
 97             edge[v].cap -= d;
 98             edge[v ^ 1].cap += d;
 99         }
100     }
101     return res;
102 }
103 
104 int main() {
105     int T;
106     scanf("%d", &T);
107     while (T--) {
108         init();
109         cin >> n >> m;
110         int s = 0, t = n + 1, f = 0;
111         rep(i, 1, n + 1) {
112             int a, b;
113             scanf("%d%d", &a, &b);
114             add_edge(s, i, a, 0);
115             add_edge(i, t, b, 0);
116             f += a;
117         }
118         while (m--) {
119             int u, v, c;
120             double p;
121             scanf("%d%d%d%lf", &u, &v, &c, &p);
122             p = -log2(1 - p);
123             if (c > 0) add_edge(u, v, 1, 0);
124             if (c > 1) add_edge(u, v, c - 1, p);
125         }
126         double p = mcf(s, t, f);
127         printf("%.2f\n", 1 - pow(2, -p));
128     }
129     return 0;
130 }

 

posted @ 2017-10-22 18:18  Flowersea  阅读(279)  评论(0编辑  收藏  举报