洛谷 P1685 - 游览

简明题意

在这里插入图片描述

思路

从深搜开始

手玩样例,我们很快(从题目后的提示)找到了 1 − 3 1 - 3 13 1 − 2 − 3 1-2-3 123 1 − 2 − 3 1 - 2 - 3 123(两者不同)一共三条路径。求出其权值之和再加上乘船返回两次所需的时间,和样例恰好一致。

于是我们便可以把这个问题分成两个子问题逐个求解:

  • 起点到终点的所有不同路径的权值总和
  • 起点到终点的所有不同路径的数目

选择从起点开始 dfs,我们需要考虑在搜索树上,我们怎样进行状态与状态之间的转移(说白了就是 dfs 函数里写什么)。

我们对症下药:题目让求起点到终点路径的权值和,我们就先存下起点到当前点路径的权值和,用 s[] 数组存储;题目让求起点到终点路径的数目,我们就先存下起点到当前点路径的数目,用 cnt[] 数组存储。

搜索树上,父亲想要告诉儿子什么呢?肯定就是 s[fa]cnt[fa] 的数值了。那么作为父亲最喜爱的儿子(误),怎样处理好父亲给的信息呢?我们具体分析。

在这里插入图片描述

假设我们当前节点(父亲)为 2,即将处理的边为 权值为 $ 7 $ 的边,那么儿子节点就是 3。 我们发现有了这条边之后,1 -> 2 的每一条路径都可以和它组合,成为 1 -> 3 的一条新路径。

因此这条边对于权值之和的贡献是:通过 1 -> 2 的每一条不相同的路和这条边的权值总和。这条边对于路径数量的贡献,就是 1 -> 2 的路径数量。

比如:假设 12 3 3 3 条边,23 5 5 5 条边,那么根据乘法原理 1 -> 2 -> 3 3 × 5 3 \times 5 3×5 条边,在我们分别处理 23 5 5 5 条边时,每一条边都会造成 3 3 3 条新路径的贡献,这和乘法原理是相符的。对于权值的求和也可以从上面的假设去理解。

因此我们处理一条从 u 指向 to ,边权为 w 的边,那么:

s t o = ∑ w × c n t u + s u s_{to}= \sum w \times cnt_u + s_u sto=w×cntu+su

而对于 to ,路径数量则是:

c n t t o = ∑ c n t u cnt_{to} = \sum cnt_u cntto=cntu

有如下代码:

void dfs(int u)
{
    for (int k = head[u]; k; k = nxt[k])
    {
        cnt[to] += cnt[u];
        s[to] += mul(edge[k], cnt[u])) + s[u];
        dfs(to);
    }
}

然而当你用这个做法兴奋地提交之后,才发现自己获得了 20 分(或者是 0 分)的好成绩。

调整搜索顺序

你可能会抱怨道:为什么!我样例明明过了啊!然而作为一名 OIer, 绝对不能 Too Young Too Simple,样例往往太简单,只是辅助理解题意的,并不能帮你找出 bug 来。

我再给一组样例,在你读完题解前,希望对你有所启发:

输入为:

4 6 1 3 1
1 2 1
1 2 1
2 3 1
1 4 1
1 4 1
4 3 1

输出为:

11

在这里插入图片描述
如图,由于边输入顺序的原因(我选用链式前向星存图),导致 4 号点在还没有处理完,得到正确的 scnt 值时,就向 3 传递了信息,最后造成统计错误。

因此我们希望,改变搜索顺序,让每一个节点把自己的数据处理好,再向下一个节点汇报。 有没有这样的方法呢?答案是有的,那就是拓扑排序

我们记录每一个节点此时的入度,处理完一条边入度自减 $ 1 $,当入度为 $ 0 $ 时加入搜索队列,那么我们就可以保证每个点都得到了正确的结果。

代码

因此最终代码如下:(注意处理取模

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int MAXN = 1e4 + 50, MAXM = 5e4 + 50, INF = 0x3f3f3f3f, MOD = 1e4;
int head[MAXN], nxt[MAXM], ver[MAXM], edge[MAXM], tot; // 链式前向星相关
int cnt[MAXN], s[MAXN], in[MAXN]; // 本题相关
bool vis[MAXM]; // 记录某条边是否走过(或许不需要)
inline void add(int u, int v, int w) 
{
    in[v]++; // 记录入度
    ver[++tot] = v;
    edge[tot] = w;
    nxt[tot] = head[u];
    head[u] = tot;
}
inline int mul(int a, int b) { return ((a % MOD) * (b % MOD)) % MOD; } // 一步三取模,被取模错误丢分吓怕了
inline void topo(int start) // 拓扑排序的同时进行递推
{
    queue<int> q;
    cnt[start] = 1;
    q.push(start);
    while (q.size())
    {
        int u = q.front(); q.pop();
        for (int k = head[u]; k; k = nxt[k])
        {
            if (vis[k]) continue;
            int to = ver[k]; 
            vis[k] = true; in[to]--;
            cnt[to] = (cnt[to] + cnt[u]) % MOD;
            s[to] = (((s[to] % MOD) + mul(edge[k], cnt[u])) % MOD + s[u]) % MOD;
            if (in[to] == 0) q.push(to); // 入度为 0 加入队列
        }
    }
}
int main()
{
    int n, m, start, t, ts;
    scanf("%d %d %d %d %d", &n, &m, &start, &t, &ts); // 简简单单的输入
    for (int i = 1; i <= m; ++i)
    {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w);
    }
    topo(start);
    int ans = (s[t] + mul(ts, cnt[t] - 1) + MOD) % MOD; // 别忘了把路径数量 - 1乘上乘船时间
    printf("%d", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值