重聚

自创第一题

题目背景

最好的朋友在身边,最爱的人就在对面.

自爱情公寓拆迁已经过去十多年……

多年过后,曾经爱情公寓的每个人都成为了自己想成为的样子,一菲成为了著作等身的大教授兼弹一闪道馆馆主,小贤主持的新《你的太阳我的心》大火,咖喱酱成为了娱乐圈配音界的扛把子,子乔和美嘉把事业做大了,成为了人生赢家,海棠成为了一代文豪,大力在火星上研究水稻,张伟则跟随大力成为了火星上有名的大律师。这一天,海棠邀请朋友们来参加掘地重工举办的世界博览会,就这样,大家再一次重聚,踏上了世博会之旅……

题目描述

这次博览会一共有(n)个展厅,编号从(1)(n),且这些展厅是由单向道路连接的,掘地重工的工作人员们对这次博览会的路线进行了精心的设计,使得这次博览会的展厅之间不存在循环路线。

起初,小伙伴们在(1)号展厅,这次旅行的终点在(n)号展览厅---爱情公寓厅,这是掘地重工给爱情公寓的小伙伴们专门准备的礼物。因为他们想要尽快到达(n)号厅而又想尽量多的参观别的展厅,所以他们想在(t)个时间单位内到达(n)号厅。

假设参观展厅不需要花费时间,现在你的任务就是帮助他们在不超过(t)的时间内确定从(1)号展厅到(n)号展厅的旅程中最多可以参观多少个展厅。保证至少有一条从(1)号展厅到(n)号展厅的路线,并保证这条道路小伙伴们将花费不超过(t)个时间单位通过。

输入格式

第一行三个整数(n, m, t),分别表示展厅的数量、展厅之间的道路数量以及时间限制。

接下来(m)行,每行三个整数(x,y,w),表示从(x)号展厅到(y)号展厅有一条花费时间(w)的路线

输出格式

第一行一个整数(ans),表示最多可以参观的展厅数量。

第二行(ans)个整数,按访问顺序输出路径(即每个访问到的点)

数据范围

对于(30%)的数据满足:(2≤n≤10),(1≤m≤10)

对于(100%)的数据满足:(2≤n≤5000,1≤m≤5000,t≤10^9,1≤w≤10^9)

(256MB)

注意

绝对良心题吧嘻嘻(qwq)

小清新简单题,用来休闲

solution

一句话题意

有一个(n)个点(m)条边的有向无环图,求从(1)(n)总路径长度不超过(t),且经过点最多的路径。

题解

拓扑排序+(DP)

说实话其实不用给部分分……

很显然,题目中给出的图是一个(DAG)(有向无环图)

因为(n)(m)只有(5000),所以我们可以大胆地写一个(O(nm))的算法。

因为要求最短路径,且图中无环,所以我们可以大胆地(DP)来做

用一个二维数组(f[i][j])表示从(1)号点到(i)号点经过(j)个点的最短路径(初始化(inf)),最后只要从大到小判断第一个(f[n][i]le t)(i)即可,同时,为了保证每个点都是最小值,(DP)要按照拓扑序的顺序(而不是节点序),因为是(DAG)嘛~

转移:(f[x][j] = min(f[x][j], f[x][j - 1]+e[i].val))((i)(x)的连边,(j=[2)~(n]))

再一个问题就是记录路径了,我们可以在(DP)过程中用一个类似于(f)数组的(pre)数组,(pre[i][j])表示从(1)走到(i),经过了(j)个点的上一个节点的编号,输出的时候可以用(stack)记录,也可以直接回溯

代码

#include <stack>
#include <queue> 
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e3 + 11;
const int INF = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
	for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, d, cnt, head[A];
struct node { int to, nxt, val; } e[A];
int f[A][A], pre[A][A], rdu[A], mx;;
vector <int> s;
stack <int> path;

inline void add(int from, int to, int val) {
    e[cnt].to = to;
    e[cnt].val = val;
    e[cnt].nxt = head[from];
	head[from] = cnt++;
}

void topo() {  //拓扑排序
    queue <int> q;
    for (int i = 1; i <= n; i++) if (rdu[i] == 0) q.push(i);
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        s.push_back(x);
        for (int i = head[x]; i != -1; i = e[i].nxt)
    		if ((--rdu[e[i].to]) == 0) q.push(e[i].to);
    }
}

signed main() {
	freopen("5.in", "r", stdin);
	freopen("5.out", "w", stdout);
    memset(f, INF, sizeof(f));
    memset(pre, -1, sizeof(pre));
    memset(head, -1, sizeof(head));
	n = read(), m = read(), d = read();
    for (int i = 1, x, y, z; i <= m; i++) {
    	x = read(), y = read(), z = read();
        add(x, y, z);
        rdu[y]++;
    }
    topo();
    f[1][1] = 0;
    for (int k = 0; k < s.size(); k++) {
        int x = s[k];
        for (int i = head[x]; i != -1; i = e[i].nxt)
            for (int j = 2; j <= n; j++)
                if (f[x][j - 1] + e[i].val < f[e[i].to][j]) { 
                    f[e[i].to][j] = f[x][j - 1] + e[i].val;
                    pre[e[i].to][j] = x;
                }
    }
    for (int i = n; i >= 1; i--)
        if (f[n][i] <= d) {
            mx = i;
            break;
        }
    cout << mx << '
';
    int pos = n, dep = mx;
    while (pos != -1) {
        path.push(pos);
        pos = pre[pos][dep];
        dep--;
    }
    while (!path.empty()) {
        cout << path.top() << ' '; 
        path.pop();
    }
	cout << '
';
    return 0;
}
原文地址:https://www.cnblogs.com/loceaner/p/12337074.html