题目:
马上就要新年了,先祝大家新年快乐!
小Z不久就要回老家过新年了,是时候来筹划一下自己的路线了。他查了百度地图,发现一路上有N个城市,编号为1到N。并且有R条单向道路。
可是,每一条道路,竟然都有过路费(都新年了还坑钱)!所以小Z不得不详细查清楚每一条道路所连接的两个城市,长度以及过路费。
可惜,小Z毕竟是同学,只有K元零花钱,但是他想从杭州(城市1)走到龙游(城市N),问最短共需要走多长的路。
如果无路可走,那么输出-1。
输入:
第一行,输入一个数K,表示小Z的零花钱。
第二行,输入一个数N,表示有N个城市。
第三行,输入一个数R,表示有R条道路。
接下来R行,每行输入S,D,L,T,表示从S城市到D城市的路长度为L,费用为T。
输出:
输出在费用允许的情况下,小Z走的最短路程。
输入:
5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
输出:
11
【数据范围】
对于20%的数据,$2 <= n <= 10, 0 <= K <= 10000$
对于100%的数据,$2 <= n <= 50, 0 <= K <= 10000$
$ 1 <= R <= 100000, 1 <= S <= N, 1 <= D <= N, 1 <= L <= 100, 0 <= T <= 100$.
Solution
$Subtask #1$
每次加入一条边,就加入邻接表或前向星里面(我是用前向星的)。从节点1开始遍历,如果访问到节点n则取最小值,这样一直爆搜即可。
时间复杂度:$O(玄学)$,分数:30分
$Subtask #2$
考虑加入一定剪枝。显然,最优性剪枝是很容易想到的。如果此时的长度已经大于等于计算出的最小长度,那么这条路肯定不是最优解了。所以,我们没必要再走这条路了,此时直接return掉。这样,复杂度会大大降低。
时间复杂度:$O(玄学)$,分数:100分
代码
#include <bits/stdc++.h> using namespace std; struct Edge { int to, nxt, l, c; }s[100005]; int head[55], cnt; bool vis[55]; int ans = (1 << 30); int k, n, r; void add(int from, int to, int len, int cost) { s[++cnt] = (Edge){to, head[from], len, cost}; head[from] = cnt; } void dfs(int p, int cost, int l) { if (p == n) { ans = min(ans, l); return ; } for (int i = head[p]; i; i = s[i].nxt) { if (vis[s[i].to]) continue; if (cost + s[i].c <= k && l + s[i].l < ans) { vis[s[i].to] = true; dfs(s[i].to, cost + s[i].c, l + s[i].l); vis[s[i].to] = false; } } } int main() { scanf("%d%d%d", &k, &n, &r); while (r--) { int S, D, L, T; scanf("%d%d%d%d", &S, &D, &L, &T); add(S, D, L, T); } dfs(1, 0, 0); if (ans == 1 << 30) puts("-1"); else printf("%d\n", ans); return 0; }