[NOIP2017 提高组] 逛公园 (题解)

Step 1(30pts).

最短路计数,可以参考 [NOI2007] 社交网络。

Step 2(70pts)

考虑图中没有 0 0 0 边的情况,此时是必然有解的。用 d ( u ) d(u) d(u) 表示从 1 1 1 u u u 的最短路径长度,那么要求的答案就是从 1 1 1 n n n 的长度不超过 d ( n ) + K d(n)+K d(n)+K 的路径。这个问题可以用 DP 求解,设 f ( u ; k ) f(u;k) f(u;k) 表示从 1 1 1 u u u 的长度为 d ( u ) + k d(u)+k d(u)+k 的路径数,则转移如下
f ( u ; k ) = ∑ ( v , u , w ) ∈ E f ( v ; k − w + ( d ( u ) − d ( v ) ) ) f(u;k) = \sum_{(v,u,w)\in E} f(v;k-w+(d(u)-d(v))) f(u;k)=(v,u,w)Ef(v;kw+(d(u)d(v)))
至于按照什么顺序转移,无需考虑太多,直接记忆化搜索即可

int dfs(int u, int k) {
    if (k < 0) return 0;
    if (f[u][k] != 0) return f[u][k];
    int ret = 0;
    // G1 是反向图
    for (auto it = G1[u].begin(); it != G1[u].end(); ++it) {
        int v = it->v, w = it->w;
        ret = (ret + dfs(v, d[u] - d[v] + k - w)) % P;
    }
    return f[u][k] = ret;
}

Step 3(100pts).

现在考虑如何处理有 0 0 0 边的情况,如果直接从图上考虑是否存在 0 0 0 环,将产生十分复杂的讨论(因为有 0 0 0 环不一定会造成无穷多的解)。更合理的一种方式是直接在记忆化搜索时记录当前的搜索路径,由于 DP 的正确性的前提是所有的状态能构成一个 DAG,而如果记忆话搜索的路径出现了环,就说明有无穷多个解

int dfs(int u, int k) {
    if (k < 0) return 0;
    if (inPath[u][k]){
        flag = true; // flag 判断是否有无穷多个解
        return 0;
    }
    if (f[u][k] != 0) return f[u][k];
    inPath[u][k] = true;
    int ret = 0;
    // G1 是反向图
    for (auto it = G1[u].begin(); it != G1[u].end(); ++it) {
        int v = it->v, w = it->w;
        ret = (ret + dfs(v, d[u] - d[v] + k - w)) % P;
        if (flag) return 0;
    }
    inPath[u][k] = false;
    return f[u][k] = ret;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值