说实话这题A得有点懵。改个double就过了。。。
题
目
题目
题目
这个题目好修长。
想一想其实可以发现,最优的情况应该是在整个图里面找一条最大的流,再乘上权值P。那么我们考虑先者,那我们可以二分边的最大容量,再看看可以跑出最大流不就可以了。
上马!
另外,val,flow数组要开double。(别问我怎么知道的)
#include<cstdio>
#include<cctype>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int N = 5005, lim = (1 << 30) - 1;
const double eps = 1e-7;
double res, goal, ans, val[N], flow[N];
int d[N], p, s, t, cur[N], n, m, cnt, nxt[N], to[N], head[N];
inline int read() {
int x = 0, f = 1;
char s = getchar();
while(! isdigit(s)) {
if(s == '-')
f = -1;
s = getchar();
}
while(isdigit(s)) {
x = (x << 1) + (x << 3) + (s ^ 48);
s = getchar();
}
return x * f;
}
inline void print(int x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
void addEdge(const int u, const int v, const double w) {
to[++ cnt] = v;
nxt[cnt] = head[u];
val[cnt] = w;
flow[cnt] = w;
head[u] = cnt;
}
double dfs(const int u, const double Flow) {
if(u == t)
return Flow;
for(int &i = cur[u]; ~i; i = nxt[i]) {
int v = to[i];
if(d[v] == d[u] + 1 && flow[i] > 0) {
double dis = dfs(v, min(Flow, flow[i]));
if(dis > 0) {
flow[i] -= dis;
flow[i ^ 1] += dis;
return dis;
}
}
}
return 0;
}
bool bfs() {
queue <int> q;
while(! q.empty())
q.pop();
memset(d, 0, sizeof d);
d[s] = 1;
q.push(s);
while(! q.empty()) {
int u = q.front();
q.pop();
for(int i = head[u]; ~i; i = nxt[i]) {
int v = to[i];
if(d[v] == 0 && flow[i] > 0) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
return d[t] > 0;
}
double dinic() {
double ans = 0, dis;
while(bfs()) {
for(int i = 1; i <= n; ++ i)
cur[i] = head[i];
while(dis = dfs(s, lim))
ans += dis;
}
return ans;
}
double jdz(double x) {
if(x < 0)
return -x;
return x;
}
void init() {
for(int i = 0; i < cnt; ++ i)
flow[i] = min(goal, val[i]);
}
int main() {
int a, b, c;
double l, r, tmp;
while(scanf("%d", &n) != EOF) {
m = read();
p = read();
cnt = -1;
s = 1;
t = n;
memset(nxt, -1, sizeof nxt);
memset(head, -1, sizeof head);
for(int i = 1; i <= m; ++ i) {
a = read();
b = read();
c = read();
addEdge(a, b, c);
addEdge(b, a, 0);
}
res = dinic();
printf("%.0f\n", res);
l = 0;
r = lim;
while(r - l > eps) {
double mid = (l + r) / 2;
goal = mid;
init();
tmp = dinic();
if(jdz(tmp - res) < eps) {
ans = mid;
r = mid;
}
else
l = mid;
}
printf("%.4f\n", ans * p);
}
return 0;
}