• BZOJ 3955 Surely You Congest 解题报告


    首先,我们可以求出源为 $1$ 号点的最短路图以及各个点到 $1$ 号点的最短路。

    然后我们考虑那些距离不同的点,是一定不会发生拥堵现象的。

    然后我们就只需要考虑那些距离相同的点,就相当于做一个最大流嘛。

    假设考虑与 $1$ 号节点距离为 $d$ 的点,那怎么连边,怎么设置源和汇呢?

    • 源为 $1$ 号节点,新开一个 $n+1$ 号节点作为汇。
    • 对于所有满足 $dist(1, x) + w(x,y) = dist(1, y)$ 的 $x,y$ 建一条 $x ightarrow y$ 的边,容量为 $1$。
    • 如果某个点 $x$ 与 $1$ 号节点距离恰好为 $d$,建一条 $x ightarrow T$ 的边,容量为这个点上车辆的数目。

    然后把所有距离下的最大流加起来,就是答案了。

    复杂度看起来有点高,不过加点优化应该还是能跑过去的。

    我加了一个优化:如果与 $1$ 号节点距离为 $d$ 的车辆只有 $1$ 辆,那么最大流就是 $1$,就不用去跑网络流了。

    感觉效果还不错。

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <algorithm>
      6 using namespace std;
      7 typedef long long LL;
      8 #define C 2000 + 5
      9 #define N 50000 + 5
     10 #define M 400000 + 5
     11 #define SIZE 10000000 + 5
     12 #define INF 0x7fffffff
     13  
     14 int n, m, c, S, T, tot, _tot, ans;
     15 int A[C];
     16 int Head[N], _Head[N], Inq[N];
     17 int Dis[N], _Dis[N];
     18 int E[M][3];
     19 int q[SIZE];
     20  
     21 struct Edge
     22 {
     23     int next, node, flow, w;
     24 }h[M], _h[M];
     25  
     26 inline void addedge(int u, int v, int fl, int w)
     27 {
     28     h[++ tot].next = Head[u], Head[u] = tot;
     29     h[tot].node = v, h[tot].flow = fl, h[tot].w = w;
     30     h[++ tot].next = Head[v], Head[v] = tot;
     31     h[tot].node = u, h[tot].flow = 0, h[tot].w = w;
     32 }
     33  
     34 inline bool SPFA(int S)
     35 {
     36     for (int i = S; i <= T; i ++)
     37         Dis[i] = INF, Inq[i] = 0;
     38     int l = 1, r = 1;
     39     Dis[S] = 0, q[1] = S, Inq[S] = 1;
     40     while (l <= r)
     41     {
     42         int z = q[l ++];
     43         Inq[z] = 0;
     44         for (int i = Head[z]; i; i = h[i].next)
     45         {
     46             int d = h[i].node, p = h[i].flow, w = h[i].w;
     47             if (!p) continue ;
     48             if (Dis[d] > Dis[z] + w)
     49             {
     50                 Dis[d] = Dis[z] + w;
     51                 if (!Inq[d])
     52                 {
     53                     q[++ r] = d;
     54                     Inq[d] = r;
     55                 }
     56             }
     57             if (Inq[d] && Dis[d] < Dis[q[l]])
     58             {
     59                 int u = Inq[d], v = q[l];
     60                 q[l] = d, q[u] = v;
     61                 Inq[d] = l, Inq[v] = u;
     62             }
     63         }
     64     }
     65     return Dis[T] != INF;
     66 }
     67  
     68 inline void Copy()
     69 {
     70     _tot = tot;
     71     for (int i = S; i <= T; i ++)
     72         _Head[i] = Head[i], _Dis[i] = Dis[i];
     73     for (int i = 2; i <= tot; i ++)
     74         _h[i] = h[i];
     75 }
     76  
     77 inline void Restore()
     78 {
     79     tot = _tot;
     80     for (int i = S; i <= T; i ++)
     81         Head[i] = _Head[i];
     82     for (int i = 2; i <= _tot; i ++)
     83         h[i] = _h[i];
     84 }
     85  
     86 inline bool cmp(int u, int v)
     87 {
     88     return Dis[u] < Dis[v];
     89 }
     90  
     91 inline int dinic(int z, int inflow)
     92 {
     93     if (z == T || !inflow) return inflow;
     94     int ret = inflow, flow;
     95     for (int i = Head[z]; i; i = h[i].next)
     96     {
     97         int d = h[i].node, p = h[i].flow;
     98         if (Dis[d] != Dis[z] + 1) continue ;
     99         flow = dinic(d, min(ret, p));
    100         ret -= flow;
    101         h[i].flow -= flow, h[i ^ 1].flow += flow;
    102         if (!ret) return inflow;
    103     }
    104     if (ret == inflow) Dis[z] = -1;
    105     return inflow - ret;
    106 }
    107  
    108 int main()
    109 {
    110     #ifndef ONLINE_JUDGE
    111         freopen("3955.in", "r", stdin);
    112         freopen("3955.out", "w", stdout);
    113     #endif
    114      
    115     scanf("%d%d%d", &n, &m, &c);
    116     S = 1, T = n + 1;
    117     for (int i = 1; i <= m; i ++)
    118     {
    119         int u, v, w;
    120         scanf("%d%d%d", &u ,&v, &w);
    121         E[i][0] = u, E[i][1] = v, E[i][2] = w;
    122         addedge(u, v, 1, w);
    123         addedge(v, u, 1, w);
    124     }
    125     SPFA(1);
    126     for (int i = 1; i <= c; i ++)
    127         scanf("%d", A + i);
    128     sort(A + 1, A + c + 1, cmp);
    129     tot = 1;
    130     memset(Head, 0, sizeof(Head));
    131     for (int i = 1; i <= m; i ++)
    132     {
    133         if (Dis[E[i][0]] + E[i][2] == Dis[E[i][1]])
    134             addedge(E[i][0], E[i][1], 1, 1);
    135         if (Dis[E[i][1]] + E[i][2] == Dis[E[i][0]])
    136             addedge(E[i][1], E[i][0], 1, 1);
    137     }
    138     Copy();
    139     int l = 1, r;
    140     for (; l <= c; l = r + 1)
    141     {
    142         for (r = l; r < c && _Dis[A[r + 1]] == _Dis[A[l]]; r ++) ;
    143         if (r == l) ans ++;
    144         else
    145         {
    146             Restore();
    147             for (int i = l; i <= r; i ++)
    148                 addedge(A[i], T, 1, 1);
    149             while (SPFA(S))
    150                 ans += dinic(S, INF);
    151         }
    152     }
    153     printf("%d
    ", ans);
    154      
    155     #ifndef ONLINE_JUDGE
    156         fclose(stdin);
    157         fclose(stdout);
    158     #endif
    159     return 0;
    160 }
    3955_Gromah
  • 相关阅读:
    C#并行编程-并发集合
    使用Lucene.Net实现全文检索
    Lucene.Net 站内搜索
    lucene.net helper类 【结合盘古分词进行搜索的小例子(分页功能)】
    Spring学习之Ioc
    Hibernate向MySQL插入中文数据--乱码解决
    MySql表中key的区别
    Myeclipse中相同变量高亮显示
    Mac下配置PHP+Apache+phpMyAdmin+MySql远程链接
    JQuery实现——黑客帝国代码雨效果
  • 原文地址:https://www.cnblogs.com/gromah/p/4427728.html
Copyright © 2020-2023  润新知