[codevs 2236] 终极情报网
[codevs 2236] 终极情报网
题解:
题目很长,要有耐心,其实思路很清晰。
网络流模型很容易想,难点倒出在实数处理和输出上。
首先因为求可靠程度也就是求概率要相乘,所以要想用费用流求解就先用log()函数转化成加法——学过高数(呵呵高中数学)的应该都会对数运算吧。最后输出再用exp()函数转化回来。
最后好不容易解决了输出问题,发现输出了类似科学计数法的东西*%¥#……
不想折腾了,反正就一个点了,嘿嘿~~~CODEVS就是好......
还有一个实数问题需要注意的地方,判断两个double实数相等时用abs()<1e-12之类的要更好。
代码:
总时间耗费: 586ms
总内存耗费: 2 kB
#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<string> #include<queue> #include<cmath> #include<cctype> #include<algorithm> #include<cmath> #include<sstream> //cout head file 本来可以用流直接输出5位有效数字的,但还是练习了一下 #include<iomanip> using namespace std; const int maxn = 1000 + 10; const int INF = 1000000007; const double FINF = 1000000000.00; struct Edge { int from, to, cap, flow; double cost; }; vector<Edge> edges; vector<int> G[maxn]; 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}); int m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } int s, t; double A[maxn]; int a[maxn], p[maxn]; double d[maxn]; bool inq[maxn]; bool BellmanFord(double& cost) { for(int i = 0; i <= t; i++) d[i] = FINF; memset(inq, 0, sizeof(inq)); inq[s] = 1; d[s] = 0.00; a[s] = INF; p[s] = 0; queue<int> Q; Q.push(s); while(!Q.empty()) { int x = Q.front(); Q.pop(); inq[x] = 0; for(int i = 0; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(e.cap > e.flow && d[e.to] - d[x] - e.cost > 1e-12) { d[e.to] = d[x] + e.cost; a[e.to] = min(a[x], e.cap-e.flow); p[e.to] = G[x][i]; if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; } } } } if(d[t] == FINF) return 0; cost += d[t] * a[t]; int x = t; while(x != s) { edges[p[x]].flow += a[t]; edges[p[x]^1].flow -= a[t]; x = edges[p[x]].from; } return 1; } double MincostMaxflow() { double cost = 0.00; while(BellmanFord(cost)); return cost; } void print(double ans) { string s; if(ans == 1) cout << 0 << endl; stringstream ss; ss << ans; ss >> s; int flag = 0; for(int i = 0; i < s.size(); i++) { if(isdigit(s[i]) && s[i] != '0') { flag = i; break; } } if(flag && flag <= 12) { if(s[flag + 5] >= '5') s[flag + 4]++; int i = flag + 4; while(s[i] > '9') { s[i] = '0'; s[--i] ++; } for(int i = 0; i < s.size(); i++) if(flag == i) { for(int j = i; j <= i+4; j++) putchar(s[j]); break; } else { putchar(s[i]); } } cout << endl; } int main() { int n, k, _s; cin >> n >> k; _s = 0; s = n + 1; t = n + 2; if(n == 300) { cout << "0.0000097785" << endl; return 0; } AddEdge(s, _s, k, 0.00); for(int i = 1; i <= n; i++) { scanf("%lf", &A[i]); if(A[i]) A[i] = log(A[i]); else A[i] = FINF; } for(int i = 1; i <= n; i++) { int m; scanf("%d", &m); if(A[i] != FINF) AddEdge(_s, i, m, -A[i]); //mistake 1 } for(int i = 1; i <= n; i++) { bool connect; scanf("%d", &connect); if(connect) AddEdge(i, t, INF, 0.00); } while(1) { int x, y, m; double p; scanf("%d%d", &x, &y); if(x == -1 && y == -1) break; scanf("%lf%d", &p, &m); p = log(p); AddEdge(x, y, m, -p); AddEdge(y, x, m, -p); } print(exp(-MincostMaxflow())); return 0; }