P1807 最长路
2023-08-09 20:32:20 # OI # Problem

题面

题目描述

GG 为有 nn 个顶点的带权有向无环图,GG 中各顶点的编号为 11nn,请设计算法,计算图 GG1,n1, n 间的最长路径。

输入格式

输入的第一行有两个整数,分别代表图的点数 nn 和边数 mm

22 到第 (m+1)(m + 1) 行,每行 33 个整数 u,v,wu, v, wu<vu<v),代表存在一条从 uuvv 边权为 ww 的边。

输出格式

输出一行一个整数,代表 11nn 的最长路。

11 无法到达 nn,请输出 1-1

样例 #1

样例输入 #1

2 1
1 2 1

样例输出 #1

1

提示

【数据规模与约定】

  • 对于 20%20\%的数据,n100n \leq 100m103m \leq 10^3
  • 对于 40%40\% 的数据,n103n \leq 10^3m104m \leq 10^{4}
  • 对于 100%100\% 的数据,1n15001 \leq n \leq 15000m5×1040 \leq m \leq 5 \times 10^41u,vn1 \leq u, v \leq n105w105-10^5 \leq w \leq 10^5

思路

拓扑排序的同时进行一个 DP 就可以了。

我们定义fif_i为从11号点到ii号点距离的最大值。

然后进行拓扑排序,能被1号点到达的点就打上标记并更新答案,因为可能也有入度为0的点但是不会被起点到达的点。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1699;
const int M=5e4+5;
int n,m,cnt;
int d[N],f[N];
int bj[N];//能被一号点到达的点才能更新答案
struct edge
{
    int to,val,from;
};
vector<edge> e[1600];
void tpsort()
{
    queue<int> Q;
    for(int i=1;i<=n;i++)
        if(d[i]==0)
            Q.push(i);
    while(!Q.empty())
    {
        int x=Q.front();
        Q.pop();//枚举出边
        for(int i=0,size=e[x].size();i<size;i++)//注意vector是从0开始
        {
            int p=e[x][i].to;
            d[p]--;
            if(bj[x]==1)
                f[p]=max(f[p],f[x]+e[x][i].val),bj[p]=1;
            if(!d[p]) Q.push(p);
        }
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        edge x;
        scanf("%d%d%d",&x.from,&x.to,&x.val);
        e[x.from].push_back(x);//以from开头的第i条边(的信息)存入
        d[x.to]++;
    }
    memset(f,-1,sizeof(f));
    bj[1]=1;
    f[1]=0;//1~1距离为0
    tpsort();
    printf("%d",f[n]);
    return 0;
}