前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【洛谷-图论】P1807 最长路

【洛谷-图论】P1807 最长路

作者头像
六月丶
发布2022-12-26 17:56:18
发布2022-12-26 17:56:18
44600
代码可运行
举报
文章被收录于专栏:六月-游戏开发六月-游戏开发
运行总次数:0
代码可运行

题目描述

G 为有 n 个顶点的带权有向无环图,G 中各顶点的编号为 1n,请设计算法,计算图 G\lt1,n\gt 间的最 长路径。

输入输出格式

输入格式

输入的第一行有两个整数,分别代表图的点数 n 和边数 m。 第 2 到第 (m + 1) 行,每行 3 个整数 u, v, w,代表存在一条从 uv 边权为 w 的边。

输出格式

输出一行一个整数,代表 1n 的最长路。 若 1n 不联通,请输出 -1

输入输出样例

输入样例 #1

2 1 1 2 1

输出样例 #1

1

说明

数据规模与约定
  • 对于 20\%的数据,n \leq 100m \leq 10^3
  • 对于 40\% 的数据,n \leq 10^3m \leq 10^{4}
  • 对于 100\% 的数据,1 \leq n \leq 15001 \leq m \leq 5 \times 10^41 \leq u, v \leq n-10^5 \leq w \leq 10^5

解题思路

这题可以用拓扑排序,从顶点1出发,依次记录刷新到i点的最长路径存入f[i]中,最后输出f[n]即可。 但需要注意,题目中并没有说只有1为入度为0的顶点,也就是说还有可能存在其它入度为0的顶点,如果把这些点也加入计算,可能导致错误结果,因为求的是从1到n的最长路径不是i到n。而如果不管这些顶点,又会影响拓扑过程,因为只有当一个顶点入度为0时才会加入队列,而如果一个入度为0的顶点 i 指向另一个顶点 x ,因为顶点 i 在拓扑过程中无法到达,所以顶点 x 就永远入度大于0,导致无法进入队列,相当于封死了这条路。 所以在拓扑前还需要把这些除1外的入度为0的顶点去除。

代码语言:javascript
代码运行次数:0
复制
    //去除掉除了n以外的入度为0的点
    bool seenInd0[MAXN] = { false };        //已经去除的入度为0的顶点标记为true
    for (int idx = 2; idx <= n; idx++) {
        if (ind[idx] == 0&&seenInd0[idx]==false) {
            for (int j = 0; j < edges[idx].size(); j++) {
                int toP = edges[idx][j].first;      //到达的点
                ind[toP]--;
            }
            seenInd0[idx] = true;
            idx = 1;        //重新搜索,因为可能产生新的入度为0的点
        }
    }

完整代码

代码语言:javascript
代码运行次数:0
复制
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>

using namespace std;

const int MAXN = 1505;

vector<pair<int,int> > edges[MAXN];     //存点idx能到达点first,权值为second
int ind[MAXN],f[MAXN];                  //入度,到当前点的最大权值和
queue<int> que;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n, m,tmp1,tmp2,tmp3;
    bool find = false;      //能到达n
    cin >> n >> m;

    for (int i = 1; i <= m; i++) {
        cin >> tmp1 >> tmp2 >> tmp3;
        edges[tmp1].push_back(make_pair(tmp2, tmp3));
        ind[tmp2]++;
    }
    //去除掉除了n以外的入度为0的点
    bool seenInd0[MAXN] = { false };
    for (int idx = 2; idx <= n; idx++) {
        if (ind[idx] == 0&&seenInd0[idx]==false) {
            for (int j = 0; j < edges[idx].size(); j++) {
                int toP = edges[idx][j].first;      //到达的点
                ind[toP]--;
            }
            seenInd0[idx] = true;
            idx = 1;        //重新搜索,因为可能产生新的入度为0的点
        }
    }
    que.push(1);
    while (que.empty() == false) {
        int u = que.front();
        que.pop();
        for (int i = 0; i < edges[u].size(); i++) {
            int v = edges[u][i].first,power = edges[u][i].second;
            f[v] = max(f[v], f[u]+power);
            ind[v]--;
            if(ind[v]==0)que.push(v);
            if (v == n)find = true;         
        }
    }
    cout << (find? f[n]:-1);

    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020 年 11 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目描述
  • 输入输出格式
    • 输入格式
    • 输出格式
  • 输入输出样例
    • 输入样例 #1
    • 输出样例 #1
  • 说明
    • 数据规模与约定
  • 解题思路
  • 完整代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档