BZOJ 4055 Misc

原题传送门

比较复杂的一道DP。

设两点(i,j)之间最短路为dis[i][j],则

可转化为:

将该式前后分立,可得:

其中,可以单独求出,后面的部分则需要DP。

为b(x),枚举i,并计算出从i出发的每个点的dis。

对于每个到达的点k,b(k)可从k相邻的点的b得出。

显然,在枚举过程中可以更新一波答案:

当然,别忘了更新b值:

代码:

  1 #include <bits/stdc++.h>
  2 #define sir(i, p) for(sides *i = star[p]; i; i = i -> aftr)
  3 using namespace std;
  4 const int N = 1e3 + 5;
  5 int n, m, l, r, a[N], q[N], dis[N], ind[N];
  6 double pout[N];
  7 long double bck[N], rnt[N];
  8 priority_queue <pair <int, int> > queues;
  9 bool vis[N];
 10 struct sides {
 11     int vv, sis;
 12     sides *aftr;
 13     long double ends;
 14 }*star[N], lenss[N << 3];
 15 inline void moree (int x, int y, int z, double w) ;
 16 void pushups (int x) ;
 17 void solve (int x) {
 18     dis[x] = 0;
 19     queues.push (make_pair (0, x));
 20     while (!queues.empty()) {
 21         int u = queues.top().second;
 22         queues.pop();
 23         if (vis[u])
 24             continue;
 25         vis[u] = 1;
 26         sir (i, u)
 27             if (dis[i -> vv] > dis[u] + i -> sis) {
 28                 dis[i -> vv] = dis[u] + i -> sis;
 29                 queues.push (make_pair (-dis[i -> vv], i -> vv));
 30             }
 31     }
 32     return ;
 33 }
 34 void doit (int x) {
 35     for (int p = r; p > 1; p --) {
 36         int u = q[p];
 37         sir (i, u)
 38             if(dis[i->vv] == dis[u]+i->sis) {
 39                 int v = i->vv; bck[u] += i->ends*bck[v];
 40             }
 41         pout[u] += a[x]*rnt[u]*bck[u];
 42         bck[u] += (long double)a[u]/rnt[u];
 43     }
 44     return ;
 45 }
 46 int main() {
 47     scanf ("%d%d", &n, &m);
 48     for (int i = 1; i <= n; i ++)
 49         scanf("%d", &a[i]);
 50     for (int i = 1; i <= m; i ++) {
 51         int x, y, z;
 52         double w;
 53         scanf("%d%d%d%lf", &x, &y, &z, &w);
 54         moree(x, y, z, w);
 55     }
 56     for (int i = 1; i <= n; i ++) {
 57         memset (rnt, 0, sizeof rnt);
 58         memset (bck, 0, sizeof bck);
 59         memset (vis, 0, sizeof vis);
 60         memset (dis, 0x3f, sizeof dis);
 61         solve (i);
 62         pushups (i);
 63         doit (i);
 64     }
 65     for (int i = 1; i <= n; i ++)
 66         printf ("%.10f\n", pout[i]);
 67     return 0;
 68 }
 69 inline void moree (int x, int y, int z, double w) {
 70     static int _; sides* ls;
 71     ls = &lenss[++_];
 72     ls -> vv = y;
 73     ls -> sis = z;
 74     ls -> ends = w;
 75     ls -> aftr = star[x];
 76     star[x] = ls;
 77     ls = &lenss[++_];
 78     ls -> vv = x;
 79     ls -> sis = z;
 80     ls -> ends = w;
 81     ls -> aftr = star[y];
 82     star[y] = ls;
 83     return ;
 84 }
 85 void pushups (int x) {
 86     q[r = 1] = x;
 87     l = 0;
 88     rnt[x] = 1;
 89     for (int i = 1; i <= n; i ++)
 90         sir (j, i) {
 91             if (dis[i] + j -> sis == dis[j -> vv])
 92                 ind[j -> vv] ++;
 93         }
 94     while (r > l) {
 95         int u = q[++ l];
 96         sir(i, u)
 97             if (dis[u] + i -> sis == dis[i -> vv]) {
 98                 if (!-- ind[i -> vv])
 99                     q[++r] = i -> vv;
100                 rnt[i -> vv] += rnt[u] * i -> ends;
101             }
102     }
103     return ;
104 }

 

posted @ 2020-06-13 18:13  HarryHuang  阅读(131)  评论(0编辑  收藏  举报