zoukankan      html  css  js  c++  java
  • Luogu 3953[NOIP2017] 逛公园 堆优化dijkstra + 记忆化搜索

    题解

    首先肯定是要求出单源最短路的,我用了堆优化dijikstra ,复杂度 mlogm,值得拥有!(只不过我在定义优先队列时把greater 打成了 less调了好久

    然后我们就求出了$i$到源点的最短距离$dis_i$

     

    定义一个数组 $f_{i, k}$表示从源点到节点$i$的距离比$dis_i$大$k$的路径数,另外一个数组$sch_{i,k}$ 记录某条路径上 该状态是否存在, 若在某条路径上出现了第二次, 并且$k <= K$,则可判断有符合条件的$0$环

    对于要求的$f_{i, k}$ 需要求出它所有的前驱状态(也就是拓扑), 设它的某一前驱为 $f_{u,t}$则$t = dis_i + k - dis_u - w$ ,$w$为边权。

     

    由于$t + dis_u + w = k + dis_i$, 所以$t - k = dis_i -dis_u - w$, 因为$dis_i$是到 $i$ 的最短距离, 则显然 $dis_i <= dis_u + w$, 得出$t  <= k$, 也就是某个点前驱的 $k$值会不断减小,只需要$k >= 0$ 即可进行转移。

    有转移方程 : $f_{i, k} = sum f_{u,t}$      $t >= 0$。 边界为 $f_{1, 0} = 1$。但是若设$f_{1, 0} = 1$为边界状态的话,对于经过 点 $1$ 的0环就无法判断了。

    所以我把边界定为$f_{0,0} = 1$,再从 $1 - > 0$连一条 记忆化搜索时需要记录前驱的反向,边权为0, 这样就可以解决$0$环的问题。

    最后的答案$ans = sumlimits_{k=0}^Kf_{n,k}$

    总时间复杂度为$O(MlogM + KN)$

    代码

     1 #include<cstring>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<queue>
     5 #include<vector>
     6 #define rd read()
     7 using namespace std;
     8 typedef pair<int,int> P;//用pair来存储dis 与点, 第一个关键字优先排序
     9 
    10 const int N = 1e5 + 1e4;
    11 
    12 int n, m, K, T, head[N], tot, dis[N], f[N][55], mod;
    13 vector<int>q[N], w[N];//记录前驱的反向边
    14 
    15 bool vis[N], sch[N][55], flag = true;
    16 
    17 priority_queue<P ,vector<P>, greater<P> > pq;//优先队列
    18 
    19 struct edge {
    20     int u, v, c, nxt;
    21 }e[N << 1];
    22 
    23 int read() {
    24     int X = 0, p = 1; char c = getchar();
    25     for(; c > '9' || c < '0'; c = getchar() ) if( c == '-' ) p = -1;
    26     for(; c >= '0' && c <= '9'; c = getchar() ) X = X * 10 + c - '0';
    27     return X * p;
    28 }
    29 
    30 void add( int u, int v, int c ) {
    31     e[++tot].u = u;
    32     e[tot].v = v;
    33     e[tot].c = c;
    34     e[tot].nxt = head[u];
    35     head[u] = tot;
    36 }
    37 
    38 void dij() {//求单源最短路
    39     memset( vis, 0, sizeof(vis));
    40     memset( dis, 0x3f, sizeof(dis));
    41     pq.push(P(0, 1));
    42     dis[1] = 0;
    43     for( P u, v; !pq.empty(); ) {
    44         u = pq.top(); pq.pop();
    45         int x = u.second;
    46         if(vis[x]) continue;
    47         vis[x] = 1;
    48         for( int i = head[x], nt; i; i = e[i].nxt ) if( dis[nt = e[i].v] > dis[x] + e[i].c && !vis[nt] ) {
    49             dis[nt] = dis[x] + e[i].c;
    50             pq.push(P(dis[nt], nt));
    51         }
    52     }
    53 }
    54 
    55 int dp( int u, int k ) {//记忆化搜索
    56     if( u == 0 && k == 0 ) return 1;
    57     if( f[u][k] != -1 ) return f[u][k];
    58     f[u][k] = 0;
    59     sch[u][k] = 1;
    60     for( int i = 0; i < (int)q[u].size(); ++i ) {
    61         int nt = q[u][i], t = dis[u] + k - dis[nt] - w[u][i];
    62         if(t < 0) continue;
    63         if( sch[nt][t] ) flag = false;//记录路径上的状态
    64         f[u][k] = (f[u][k] + dp(nt, t)) % mod;
    65     }
    66     sch[u][k] = 0;//回溯
    67     return f[u][k];
    68 }
    69 
    70 int main()
    71 {
    72     T = rd;
    73     for(; T; T-- ) {
    74         flag = true;
    75         memset(f, -1, sizeof(f));
    76         memset(head, 0, sizeof(head));
    77         memset(sch, 0, sizeof(sch));
    78         tot = 0;
    79         for( int i = 1; i <= n; ++i ) q[i].clear(), w[i].clear();
    80         n = rd; m = rd; K = rd; mod = rd;
    81         for( int i = 1; i <= m; ++i ) {
    82             int u = rd, v = rd, c = rd;
    83             add(u, v, c);
    84             q[v].push_back(u);
    85             w[v].push_back(c);
    86         }
    87         q[1].push_back(0);
    88         w[1].push_back(0);
    89         dij();
    90         dis[0] = 0;
    91         int ans = 0;
    92         for( int i = 0; i <= K; ++i ) ans = (ans + dp(n, i)) % mod;
    93         if(!flag) printf("-1
    ");
    94         else printf("%d
    ", ans);
    95     }
    96 }
    View Code
  • 相关阅读:
    228. Summary Ranges
    227. Basic Calculator II
    224. Basic Calculator
    222. Count Complete Tree Nodes
    223. Rectangle Area
    221. Maximal Square
    220. Contains Duplicate III
    219. Contains Duplicate II
    217. Contains Duplicate
    Java编程思想 4th 第4章 控制执行流程
  • 原文地址:https://www.cnblogs.com/cychester/p/9489419.html
Copyright © 2011-2022 走看看