Description
In ICPCCamp, there are
n cities and
m unidirectional roads between cities. The
i-th road goes from the a
i-th city to the b
i-th city. For each pair of cities
u and
v, there is at most one road from
u to
v.
As traffic in ICPCCamp is becoming heavier, toll of the roads also varies. At time
t, one should pay (c
i⋅t+d
i) dollars to travel along the
i-th road.
Bobo living in the 1-st city would like to go to the n-th city. He wants to know the average money he must spend at least if he starts from city 1 at
t∈[0,T]. Note that since Bobo's car is super-fast, traveling on the roads costs him
no time.
Formally, if
f(t) is the minimum money he should pay from city 1 to city
n at time
t, Bobo would like to find
Input
The first line contains 3 integers n,m,T (2≤n≤10,1≤m≤n(n-1),1≤T≤10
4).
The i-th of the following m lines contains 4 integers a
i,b
i,c
i,d
i (1≤a
i,b
i≤n,a
i≠b
i,0≤c
i,d
i≤10
3).
It is guaranteed that Bobo is able to drive from city 1 to city n.
Output
A floating number denotes the answer. It will be considered correct if its absolute or relative error does not exceed 10
-6.
Sample Input
3 3 2
1 2 1 0
2 3 1 0
1 3 1 1
3 3 2
1 2 1 0
2 3 1 0
1 3 0 5
Sample Output
1.750000002.00000000
有一个积分公式,看似很难的题。
稍微分析一下,其实可以发现,因为c和d是非负整数,显然,从1到n的花费只会随时间增加而增加。
并且,可以发现,对于同一时间,我们会优先选择通过路上∑ci较小的路,因为∑di是不会随时间变动的。
于是,可以以∑ci分段,对于同一段里,∑ci和∑di一定是相同的,
这一段的积分就是(r-l)*((r+l)/2)*∑ci+∑di),最后加起来除于t即可。
#include<set> #include<map> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<bitset> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #define rep(i,j,k) for (int i = j; i <= k; i++) #define per(i,j,k) for (int i = j; i >= k; i--) #define loop(i,j,k) for (int i = j;i != -1; i = k[i]) #define lson x << 1, l, mid #define rson x << 1 | 1, mid + 1, r #define ff first #define ss second #define mp(i,j) make_pair(i,j) #define pb push_back #define pii pair<int,int> #define in(x) scanf("%d", &x); using namespace std; typedef long long LL; const int low(int x) { return x&-x; } const double eps = 1e-8; const int INF = 0x7FFFFFFF; const int mod = 1e9 + 7; const int N = 15; int n, m, t, x, y; int c[N][N], d[N][N]; double dis[N]; int u[N], v[N], vis[N]; pii check(double t) { rep(i, 1, n) dis[i] = -1, u[i] = v[i] = vis[i] = 0; dis[1] = 0; while (true) { x = 0; rep(i, 1, n) { if (dis[i] < 0 || vis[i]) continue; if (!x || dis[i] < dis[x]) x = i; } if (!x) break; vis[x] = 1; rep(i, 1, n) { if (c[x][i] == -1) continue; if (dis[i]<0 || dis[i] - eps > dis[x] + t*c[x][i] + d[x][i]) { dis[i] = dis[x] + t*c[x][i] + d[x][i]; u[i] = u[x] + c[x][i]; v[i] = v[x] + d[x][i]; } else if (fabs(dis[x] + t*c[x][i] + d[x][i] - dis[i]) < eps) { if (u[i] > u[x] + c[x][i]) { u[i] = u[x] + c[x][i]; v[i] = v[x] + d[x][i]; } } } } return mp(u[n], v[n]); } int main() { while (scanf("%d%d%d", &n, &m, &t) != EOF) { memset(c, -1, sizeof(c)); while (m--) { scanf("%d%d", &x, &y); scanf("%d%d", &c[x][y], &d[x][y]); } double l = 0, r = t, ans = 0; pii bef = check(l); while (l + eps < r) { double q = l, h = r; pii now; while (q + eps < h) { now = check((q + h) / 2); if (now.ff == bef.ff) q = (q + h) / 2; else h = (q + h) / 2; } ans += (h - l) * ((h + l) / 2 * bef.ff + bef.ss); bef = check(l = h); } printf("%.8lf\n", ans / t); } return 0; }
去翻了翻网上的题解,看到的全是simpson求积分,吓得我赶紧去学了一发,原来还有这么好用的东西。#include<set> #include<map> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<bitset> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #define rep(i,j,k) for (int i = j; i <= k; i++) #define per(i,j,k) for (int i = j; i >= k; i--) #define loop(i,j,k) for (int i = j;i != -1; i = k[i]) #define lson x << 1, l, mid #define rson x << 1 | 1, mid + 1, r #define ff first #define ss second #define mp(i,j) make_pair(i,j) #define pb push_back #define pii pair<int,int> #define in(x) scanf("%d", &x); using namespace std; typedef long long LL; const int low(int x) { return x&-x; } const double eps = 1e-8; const int INF = 0x7FFFFFFF; const int mod = 1e9 + 7; const int N = 15; int n, m, t, x, y; int c[N][N], d[N][N]; double dis[N]; int vis[N]; double get(double t) { rep(i, 1, n) dis[i] = -1, vis[i] = 0; dis[1] = 0; while (true) { x = 0; rep(i, 1, n) { if (dis[i] < 0 || vis[i]) continue; if (!x || dis[i] < dis[x]) x = i; } if (!x) break; vis[x] = 1; rep(i, 1, n) { if (c[x][i] == -1) continue; if (dis[i] > eps && dis[i] + eps < dis[x] + t*c[x][i] + d[x][i]) continue; dis[i] = dis[x] + t * c[x][i] + d[x][i]; } } return dis[n]; } double simpson(double l, double r) { return (r - l) / 6 * (get(l) + 4 * get((l + r) / 2) + get(r)); } double solve(double l, double r) { double mid = (l + r) / 2, now = simpson(l, r); if (fabs(simpson(l, mid) + simpson(mid, r) - now) < eps) return now; return solve(l, mid) + solve(mid, r); } int main() { while (scanf("%d%d%d", &n, &m, &t) != EOF) { memset(c, -1, sizeof(c)); while (m--) { scanf("%d%d", &x, &y); scanf("%d%d", &c[x][y], &d[x][y]); } printf("%.8lf\n", solve(0, t) / t); } return 0; }