[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;
}