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
  • 相关阅读:
    10个很有用的高级Git命令
    25套用于Web UI设计的免费PSD网页元素模板
    101个MySQL 的调节和优化的提示
    10款最新且超实用的开发框架
    30 个有用的 HTML5 和 CSS3 表单设计
    cetos7最小化安装设置网络启动和更新yum源
    百度地图api开发:根据坐标获得地理描述地址
    防止sql注入的函数addslashes()
    jquery使用ajax提交form表单
    Git常用命令
  • 原文地址:https://www.cnblogs.com/cychester/p/9489419.html
Copyright © 2011-2022 走看看