洛谷 T63722 回家

题目:

马上就要新年了,先祝大家新年快乐!

小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;
}

猜你喜欢

转载自www.cnblogs.com/wlzhouzhuan/p/10161417.html