京东笔试0817第3题
这是一道京东笔试题目,属于动态规划中等难度题目
题目描述
第一行三个整数n,m,a(1≤n≤100,1≤m≤1000,1≤a≤1000),含义如题面所示。 接下来m行,第i行三个整数 $u_i$,$v_i$, $w_i(1 ≤ u_i,v_i \le n,1≤ w_i ≤ a)$,描述了一条道路。
输出描述
如果牛牛回家的方家数大于等于 20220201种,请你在第一行输出All roads lead to Home!,然后在第二行输出回家的方案数对 20220201 取模的结里
否则只需要输出一行一个整数,表示牛牛回家的方案数。
样例
输入
1 | 3 6 2 |
输出
1 | 9 |
说明
1 | 从城市一到城市二有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,这个还是比较好想的。
1 |
|