运输中转站计数
华为笔试真题 10月28号 第一题 100分题型
题目内容
一家物流企业共有 NNN 座中转站,各站依次标记为 111 至 NNN。站点间铺设了若干运输线路,每条线路都只支持指定方向的运输。
现已获得该网络的全部线路资料,需要回答一次运输路径计数问题。
请统计从中转站 SSS 启程、沿线路移动恰好 LLL 次后停在中转站 TTT 的路径总数。同一站点可以在途中反复到访,已经走过的线路也能够再次使用。只要经过的站点序列有一处不同,就视为两条不同路径。
输入描述
- 首行给出两个整数 NNN、MMM,依次代表站点总数和线路总数。
- 下一行给出三个整数 SSS、TTT、LLL,依次代表出发站、目的站和必须使用的线路条数。
- 随后有 MMM 行,各行给出整数 uuu、vvv,说明存在一条由站点 uuu 驶向站点 vvv 的线路。
约束: - 1≤N≤201 \le N \le 201≤N≤20。
- 1≤M≤2001 \le M \le 2001≤M≤200。
- 1≤L≤101 \le L \le 101≤L≤10。
- 1≤u,v≤N1 \le u,v \le N1≤u,v≤N。
- 1≤S,T≤N1 \le S,T \le N1≤S,T≤N。
- u≠vu \ne vu=v,即线路不会连接站点自身。
- 任意一对有序站点之间至多存在一条线路。
输出描述
输出一个整数,表示符合要求的路径总数;若没有可行路径,则输出 000。答案无需取模。
样例1
输入:
5 7
2 5 4
2 3
3 2
3 4
4 3
3 5
2 5
5 1
输出
2
解释:
从站点 222 启程,使用 444 条线路后停在站点 555,有以下两种走法:
- 2→3→2→3→52 \to 3 \to 2 \to 3 \to 52→3→2→3→5。
- 2→3→4→3→52 \to 3 \to 4 \to 3 \to 52→3→4→3→5。
两种走法都再次到访了站点 333。
样例2
输入:
6 6
2 6 2
2 1
1 6
2 4
4 6
2 5
5 6
输出:
3
解释:
由站点 222 出发,使用 222 条线路到站点 666,可选择 2→1→62 \to 1 \to 62→1→6、2→4→62 \to 4 \to 62→4→6 或 2→5→62 \to 5 \to 62→5→6。
样例 3
输入:
5 4
4 1 1
4 2
2 1
1 5
5 3
输出:
0
解释:
站点 444 没有直接驶向站点 111 的线路,因此只使用 111 条线路无法抵达目的站。
题解和思路
思路
实现思路:动态规划
- 定义
dp数组,其中dp[i]表示当前轮到达i的路径数量。 - 上一轮可以到达的站点使用
pos进行保存,当前轮能够到达站点使用nextPos保存,对应状态转移为,对于pos中每个站点u存在u->v路径,可得到ndp[v] += dp[u], 并将v加入nextPos用于下一轮状态转移。 - 按照1、2进行L轮状态转移,最终结果为
dp[t] - 算法时间复杂度为
O(L(n + m))
C++
cpp
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
int s,t,l;
cin >> n >> m;
cin >> s >> t >> l;
vector<vector<int>> grid(n + 1);
for (int i = 0; i < m; i++) {
int u,v;
cin >> u >> v;
grid[u].push_back(v);
}
vector<int> dp(n + 1, 0);
set<int> pos;
dp[s] = 1;
pos.insert(s);
for (int i = 0; i < l; i++) {
vector<int> ndp(n + 1, 0);
set<int> nextPos;
for (auto u : pos) {
for (auto v : grid[u]) {
ndp[v] += dp[u];
nextPos.insert(v);
}
}
dp = ndp;
pos = nextPos;
}
cout << dp[t];
return 0;
}
Java
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int s = sc.nextInt();
int t = sc.nextInt();
int l = sc.nextInt();
// 邻接表
List<List<Integer>> grid = new ArrayList<>();
for (int i = 0; i <= n; i++) {
grid.add(new ArrayList<>());
}
for (int i = 0; i < m; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
grid.get(u).add(v);
}
// 当前轮到达i的路径个数
int[] dp = new int[n + 1];
Set<Integer> pos = new HashSet<>();
dp[s] = 1;
pos.add(s);
for (int i = 0; i < l; i++) {
int[] ndp = new int[n + 1];
Set<Integer> nextPos = new HashSet<>();
for (int u : pos) {
for (int v : grid.get(u)) {
ndp[v] += dp[u];
nextPos.add(v);
}
}
dp = ndp;
pos = nextPos;
}
System.out.println(dp[t]);
sc.close();
}
}
python
python
import sys
def main():
input = sys.stdin.readline
n, m = map(int, input().split())
s, t, l = map(int, input().split())
# 邻接表
grid = [[] for _ in range(n + 1)]
for _ in range(m):
u, v = map(int, input().split())
grid[u].append(v)
# 当前轮到达i的路径个数
dp = [0] * (n + 1)
pos = {s}
dp[s] = 1
for _ in range(l):
ndp = [0] * (n + 1)
next_pos = set()
for u in pos:
for v in grid[u]:
ndp[v] += dp[u]
next_pos.add(v)
dp = ndp
pos = next_pos
print(dp[t])
if __name__ == "__main__":
main()
Javascript
js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const input = [];
rl.on('line', line => {
input.push(...line.trim().split(/\s+/).filter(Boolean));
});
rl.on('close', () => {
let idx = 0;
const n = Number(input[idx++]);
const m = Number(input[idx++]);
const s = Number(input[idx++]);
const t = Number(input[idx++]);
const l = Number(input[idx++]);
// 邻接表
const grid = Array.from({ length: n + 1 }, () => []);
for (let i = 0; i < m; i++) {
const u = Number(input[idx++]);
const v = Number(input[idx++]);
grid[u].push(v);
}
// 当前轮到达i的路径个数
let dp = new Array(n + 1).fill(0);
let pos = new Set([s]);
dp[s] = 1;
for (let i = 0; i < l; i++) {
const ndp = new Array(n + 1).fill(0);
const nextPos = new Set();
for (const u of pos) {
for (const v of grid[u]) {
ndp[v] += dp[u];
nextPos.add(v);
}
}
dp = ndp;
pos = nextPos;
}
console.log(dp[t]);
});
Go
go
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var n, m int
var s, t, l int
fmt.Fscan(reader, &n, &m)
fmt.Fscan(reader, &s, &t, &l)
// 邻接表
grid := make([][]int, n+1)
for i := 0; i < m; i++ {
var u, v int
fmt.Fscan(reader, &u, &v)
grid[u] = append(grid[u], v)
}
// 当前轮到达i的路径个数
dp := make([]int, n+1)
pos := make(map[int]bool)
dp[s] = 1
pos[s] = true
for i := 0; i < l; i++ {
ndp := make([]int, n+1)
nextPos := make(map[int]bool)
for u := range pos {
for _, v := range grid[u] {
ndp[v] += dp[u]
nextPos[v] = true
}
}
dp = ndp
pos = nextPos
}
fmt.Println(dp[t])
}