京东笔试0817第三题

这是一道京东笔试题目,属于动态规划中等难度题目

题目描述

第一行三个整数n,m,a(1≤n≤100,1≤m≤1000,1≤a≤1000),含义如题面所示。 接下来m行,第i行三个整数 u i u_i ui, v i v_i vi, w i ( 1 ≤ u i , v i ≤ n , 1 ≤ w i ≤ a ) w_i(1 ≤ u_i,v_i \le n,1≤ w_i ≤ a) wi(1ui,vin,1wia),描述了一条道路。

输出描述

如果牛牛回家的方家数大于等于 20220201种,请你在第一行输出All roads lead to Home!,然后在第二行输出回家的方案数对 20220201 取模的结里

否则只需要输出一行一个整数,表示牛牛回家的方案数。

样例

输入

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

输出

9

说明

从城市一到城市二有3种不同的走法,从城市二到城市三也有3种不同的走法,根据乘法原理我们可以知道,一共有3x3=9种不同的回家方法。

题解

状态:

  • dp[i][j]表示从1到i花费j的方案数量
  • st[i][j]表示从1到i花费为j的方案数量是否超出20220201

转移方程:

dp[u][i + w] = (dp[u][i + w] + dp[v][i]) % INF;

其中更新路径由v到u,i是终点为v的花费

难点是为什么要把for (int i = 0; i < a; ++i) 写在外层?

假如写在内层,那就是算完一个节点的状态再算下一个节点的状态,同时已经算出的节点状态不会再次更新,但是如果题目的路径存在环,就导致节点状态会被反复更新,通过循环的方式不行,采用拓扑的遍历的方式同样也不行,因为拓扑遍历不能有环。
所以必须写在外层,写在外层为什么可以?写在外层是按花费更新的,花费每增加1就更新所有节点,这样必须保证如果是v更新u:

  • 那么v的状态一定是最终的正确状态,以后不会被其他节点再次更新
  • u被更新后不能在本次花费下作为v去更新其他节点

第一个条件是满足的,先看初始状态,dp[1][0]=1,只有1号节点初始花费为0有一种方案,其他节点花费为0的情况下是0。每个花费只能由花费小的来更新,所以如果遍历到m,那么所有节点小于m的花费状态一定作为v去更新了,那么m就是最终状态。

由于边权>0,所以dp[v][i]更新dp[u][j],j>i,那dp[v][j]不可能在本次花费下去更新别的节点了,因为本次花费是i。

然后就是如果最终的答案大于20220201就输出“所有路线均可”,由于计算的过程涉及取模,所以还需要定义一个st[i][j]表示从1到i花费为j的方案数量是否超出20220201,如果v更新了u,那么v是否超出模数的状态就会继承到u,这个还是比较好想的。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

const int INF = 20220201;
using namespace std;

int main() {
    int n, m, a;
    cin >> n >> m >> a;

    vector<vector<pair<int, int>>> graph(n + 1); 
    for (int i = 0; i < m; ++i) {
        int vi, ui, wi;
        cin >> vi >> ui >> wi;
        graph[vi].emplace_back(ui, wi);
    }

    vector<vector<int>> dp(n + 1, vector<int>(a + 1, 0));
    vector<vector<bool>> st(n + 1, vector<bool>(a + 1, 0));
    dp[1][0] = 1; 
   
    for (int i = 0; i < a; ++i) {
        for (int v = 1; v <= n; ++v) {
            if (dp[v][i] > 0 || st[v][i]) {  
                for (auto &[u, w] : graph[v]) {
                    if (i + w <= a) {
                        dp[u][i + w] = (dp[u][i + w] + dp[v][i]) % INF;
                        if(dp[u][i + w] + dp[v][i] >= INF) st[u][i + w] = true;
                        if(st[v][i]) st[u][i + w] = true;
                    }
                }
            }
        }
    }
    if(st[n][a]) cout << "All roads lead to Home!" << endl;
    cout << dp[n][a] << endl; 
    return 0;
}

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的Doraemon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值