1. 程式人生 > >[XSY 1539] 狂飆突進的幻想鄉

[XSY 1539] 狂飆突進的幻想鄉

time col const 0.10 spf 算法 sin rac inf

題意

  給定一張 $n$ 個點 $m$ 條邊的無向圖.

  每條邊有兩個信息 $x, y$ , 這條邊的邊權是 $ax + (1 - a)y$ .

  給定源點 $S$ 和匯點 $T$ , 求當 $a \in [0, 1]$ 時, $E(minpath(S, T))$ .

  $n \le 200, m \le 400$ .

分析1  蒙特卡洛算法 + SPFA

  不論是期望還是概率, 都是在某種量化意義下, 將試驗次數取無窮大.

  我們均勻取點, 進行 SPFA , 然後取平均值.

 1 #include <cstdio>
 2 #include <cstring>
 3
#include <cstdlib> 4 #include <cctype> 5 #include <cmath> 6 #include <ctime> 7 #include <vector> 8 using namespace std; 9 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 10 #define fore(it, x) for (register vector<Edge>::iterator it = g[x].begin(); it != g[x].end(); it++) 11
#define db double 12 inline int rd(void) { 13 int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1; 14 int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f; 15 } 16 17 const db EPS = 1e-7; 18 inline int sign(db x) { return fabs(x) < EPS ? 0
: x < 0 ? -1 : 1; } 19 inline int cmp(db x, db y) { return sign(x - y); } 20 21 const int N = 205; 22 const db INF = 1e20; 23 24 int n, m, S, T; 25 struct Edge { 26 int v; db x, y; 27 inline db d(db a) { return a * x + (1 - a) * y; } 28 }; 29 vector<Edge> g[N]; 30 31 inline void Init(int s, int t, db x, db y) { 32 g[s].push_back((Edge){t, x, y}); 33 g[t].push_back((Edge){s, x, y}); 34 } 35 36 int nT; db res; 37 int q[N], qh, qt; bool inq[N]; db dis[N]; 38 39 db SPFA(db a) { 40 memset(q, 0, sizeof q), qh = qt = 0, memset(inq, false, sizeof inq), fill(dis + 1, dis + n + 1, INF); 41 q[++qt] = S, inq[S] = true, dis[S] = 0; 42 while (qh != qt) { 43 int x = q[qh = qh % n + 1]; 44 fore(it, x) 45 if (cmp(dis[x] + it->d(a), dis[it->v]) < 0) { 46 dis[it->v] = dis[x] + it->d(a); 47 if (!inq[it->v]) 48 q[qt = qt % n + 1] = it->v, inq[it->v] = true; 49 } 50 inq[x] = false; 51 } 52 return dis[T]; 53 } 54 55 int main(void) { 56 #ifndef ONLINE_JUDGE 57 // freopen("C.in", "r", stdin); 58 #endif 59 60 srand(time(0)); 61 62 n = rd(), m = rd(), S = rd(), T = rd(); 63 F(i, 1, m) { 64 int s = rd(), t = rd(); 65 db x, y; scanf("%lf %lf", &x, &y); 66 Init(s, t, x, y); 67 } 68 69 nT = 100000000 / (5 * n); 70 db V = 1.0 / (nT-1), a = 0; // seperated equally 71 for (int t = 1; t <= nT; t++) { 72 res += (1.0 / nT) * SPFA(a); 73 a += V; 74 } 75 printf("%0.10lf\n", res); 76 77 return 0; 78 }

分析2  Simpson積分 + SPFA

  這道題要求連續性隨機變量的數學期望.

  設當 $a = x$ 時, 最短路的長度是 $f_a$ .

  那麽我們要求 $\frac{\int_0 ^ 1 f_a}{1 - 0}$ .

  Simpson積分套最短路.

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #include <cmath>
 6 #include <vector>
 7 #include <map>
 8 using namespace std;
 9 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
10 #define fore(it, x) for (register vector<Edge>::iterator it = g[x].begin(); it != g[x].end(); it++)
11 #define db double
12 inline int rd(void) {
13     int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
14     int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
15 }
16  
17 const int N = 205;
18 const db INF = 1e20;
19 
20 int n, m, S, T;
21 struct Edge { 
22     int v; db x, y;
23     inline db d(db a) { return a * x + (1 - a) * y; }
24 };
25 vector<Edge> g[N];
26  
27 inline void Init(int s, int t, db x, db y) {
28     g[s].push_back((Edge){t, x, y});
29     g[t].push_back((Edge){s, x, y});
30 }
31  
32 int q[N], qh, qt; bool inq[N]; db dis[N];
33 map<db, db> val;
34  
35 db SPFA(db a) {
36     if (val.count(a)) return val[a];
37     memset(q, 0, sizeof q), qh = qt = 0, memset(inq, false, sizeof inq), fill(dis + 1, dis + n + 1, INF);
38     q[++qt] = S, inq[S] = true, dis[S] = 0;
39     while (qh != qt) {
40         int x = q[qh = qh % n + 1];
41         fore(it, x)
42             if (dis[x] + it->d(a) < dis[it->v]) {
43                 dis[it->v] = dis[x] + it->d(a);
44                 if (!inq[it->v])
45                     q[qt = qt % n + 1] = it->v, inq[it->v] = true;
46             }
47         inq[x] = false;
48     }
49     return val[a] = dis[T];
50 }
51  
52 inline db G(db L, db R) { return (R - L) * (SPFA(L) + SPFA(R) + 4 * SPFA((L+R)/2)) / 6; }
53 db Simpson(db L, db R) {
54     db M = (L+R)/2, RA = G(L, R), RL = G(L, M), RR = G(M, R);
55     return fabs(RA - RL - RR) < 1e-6 ? RL + RR : Simpson(L, M) + Simpson(M, R);
56 }
57 
58 int main(void) {
59     #ifndef ONLINE_JUDGE
60         freopen("C.in", "r", stdin);
61     #endif
62     
63     n = rd(), m = rd(), S = rd(), T = rd();
64     F(i, 1, m) {
65         int s = rd(), t = rd();
66         db x, y; scanf("%lf %lf", &x, &y);
67         Init(s, t, x, y);
68     }   
69     printf("%0.10lf\n", Simpson(0, 1));
70     
71     return 0;
72 }

[XSY 1539] 狂飆突進的幻想鄉