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
ui-th block to the
vi
vi-th block. Your task is to solve the lunch issue. According to the arrangement, there are
si
si competitors in the i-th block. Limited to the size of table,
bi
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 pi to touch
the wires and affect the whole networks. Moreover, to protect these wires, no more than ci 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.
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 pi to touch
the wires and affect the whole networks. Moreover, to protect these wires, no more than ci 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.
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 bi ( si si , bi bi ≤ 200).
Each of the next M lines contains three integers ui ui , vi vi and ci(ci ci(ci ≤ 100) and a float-point number pi pi(0 < pi pi < 1).
It is guaranteed that there is at least one way to let every competitor has lunch.
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
0.50
题意:以桌子为节点,每张桌子上有s个选手,b袋食物,要让所有的选手都能吃上食物,然后选手在桌子连成的边 上有容量,而且除了第一次路过以外,有pi的概率破坏现场的网线(跟字面意思)。求所有选手都吃上饭且最小破坏线路的概率。
处理初始节点的时候,建立一个源点跟汇点,让 s - b > 0及选手没饭吃的连源点, s - b < 0 桌子上有饭的连汇点。
概率求我们可以 1 - (最大不破坏线路的概率) = 最小破坏线路的概率 ,用概率来代表花费。
因为求概率是乘,最短(长)路的松弛是加减。。所以取log后再跑最短路,然后最后再开方就好了。
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <algorithm> #include <vector> #include <cmath> #define INF 1e9 using namespace std; const int maxn = 200 + 10; const double esp = 1e-8; struct Edge { int from, to, cap, flow; double cost; Edge(){} Edge(int f, int t, int c, int fl, double co) : from(f), to(t), cap(c), flow(fl), cost(co){} }; struct MCMF { int n,m,s,t; vector<Edge> edges; vector<int> G[maxn]; bool inq[maxn]; //是否在队列 double d[maxn]; //Bellman_ford单源最短路径 int p[maxn]; //p[i]表从s到i的最小费用路径上的最后一条弧编号 int a[maxn]; //a[i]表示从s到i的最小残量 //初始化 void init(int n,int s,int t) { this->n = n, this->s = s, this->t = t; edges.clear(); for (int i = 0; i < n; ++i) G[i].clear(); } //添加一条有向边 void AddEdge(int from, int to, int cap, double cost) { edges.push_back(Edge(from, to, cap, 0, cost)); edges.push_back(Edge(to, from, 0, 0, -cost)); m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } //求一次增广路 bool BellmanFord(int &flow, double &cost) { for (int i = 0; i < n; ++i) d[i] = INF; memset(inq, 0, sizeof(inq)); d[s] = 0, a[s] = INF, inq[s] = true, p[s] = 0; queue<int> Q; Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for (int i = 0; i < G[u].size(); ++i) { Edge &e = edges[G[u][i]]; if (e.cap > e.flow && d[e.to] - d[u] - e.cost > esp) { d[e.to] = d[u] + e.cost; p[e.to] = G[u][i]; a[e.to] = min(a[u] ,e.cap - e.flow); if (!inq[e.to]) { Q.push(e.to); inq[e.to] = true; } } } } if (d[t] == INF) return false; flow += a[t]; cost += a[t] * d[t]; int u = t; while (u != s) { edges[p[u]].flow += a[t]; edges[p[u] ^ 1].flow -= a[t]; u = edges[p[u]].from; } return true; } //求出最小费用最大流 double Min_cost() { int flow = 0; double cost = 0.0; while (BellmanFord(flow, cost)); return cost; } }MM; int main() { //freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) { int n, m; scanf("%d%d", &n, &m); MM.init(n + 5, 0, n + 1); for (int i = 1; i <= n; ++i) { int s, b, temp; scanf("%d%d", &s, &b); temp = s - b; if (temp > 0) { MM.AddEdge(0, i, temp, 0); } else if (temp < 0) { MM.AddEdge(i, n + 1, -temp, 0); } } for (int i = 0; i < m; ++i) { int u, v, w; double cost; scanf("%d%d%d%lf", &u, &v, &w, &cost); if (w - 1 > 0) MM.AddEdge(u, v, w - 1, -log2(1 - cost)); if (w > 0) MM.AddEdge(u, v, 1, 0); } double c; c = MM.Min_cost(); printf("%.2lf\n", 1.0 - pow(2, -c)); } }