洛谷 P1807

最长路

题目描述

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

输入格式

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

2 2 2 到第 ( m + 1 ) (m + 1) (m+1) 行,每行 3 3 3 个整数 u , v , w u, v, w u,v,w u < v u<v u<v),代表存在一条从 u u u v v v 边权为 w w w 的边。

输出格式

输出一行一个整数,代表 1 1 1 n n n 的最长路。

1 1 1 无法到达 n n n,请输出 − 1 -1 1

样例 #1

样例输入 #1

2 1
1 2 1

样例输出 #1

1

所以点 1 绝对是一个没有入度的点,而且不会出现环。而这一点正好满足拓扑的要求。但是,题目并不保证只有点1是没有入度的。所以要判断其他没有入度的点。而对他们的处理是?也许你一开始会想到加入队列,那你就错了!他们本身是无法到达的点,所以根本不可能会延伸到其他地方,如果加入队列,那么就会导致个别点,甚至所有点的答案错误。那么就是不管他?还是错了!如果不管,那么他们延伸出来的点的入度永远大于0,因为还有那些点。以至于发生和上一种方法一样的错误,甚至使终点无法到达!那么解决方法就是先做一遍 for 循环,找到那些点,再把延伸出来的点的入度 −1,如果这些点入度−1 后又变成了入度为 0 的点,那么再做同样的处理。

提示

【数据规模与约定】

  • 对于 20 % 20\% 20%的数据, n ≤ 100 n \leq 100 n100 m ≤ 1 0 3 m \leq 10^3 m103
  • 对于 40 % 40\% 40% 的数据, n ≤ 1 0 3 n \leq 10^3 n103 m ≤ 1 0 4 m \leq 10^{4} m104
  • 对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1500 1 \leq n \leq 1500 1n1500 0 ≤ m ≤ 5 × 1 0 4 0 \leq m \leq 5 \times 10^4 0m5×104 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1u,vn − 1 0 5 ≤ w ≤ 1 0 5 -10^5 \leq w \leq 10^5 105w105
#include <bits/stdc++.h>
using namespace std;
#define MAX 1505
vector<int> nextt[MAX],value[MAX];//记录邻接边以及对应权值 
long long len[MAX]; 
int in[MAX] = {0};
queue<int> q;//放入度为0的点 
int main()
{
	for(int i=0;i<MAX;i++) len[i] = -1e9;//初始化 放在下面的循环可以减少时间  
	len[1] = 0; 
	//记得第一个点距离应该是0 
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int a,b,v;
		cin>>a>>b>>v;
		nextt[a].push_back(b);
		value[a].push_back(v);
		in[b]++;
	 } 
	//去除除了1之外其他入度为0的点的影响
	for(int i = 2;i<=n;i++)
	{
		if(in[i] == 0)
		{
			q.push(i);
		}
	 } 
	while(!q.empty())
	{
		int now = q.front();
		q.pop();
		for(int i=0;i<nextt[now].size();i++)
		{
//			if(!--in[i]) q.push(i);  错啦!
			if(!--in[nextt[now][i]])  q.push(nextt[now][i]);
		}
	}
	q.push(1);
	while(!q.empty())
	{
		int now = q.front();
		q.pop();
		for(int i=0;i<nextt[now].size();i++)
		{
			if(len[nextt[now][i]]<len[now]+value[now][i]) 
				len[nextt[now][i]]=len[now]+value[now][i];
			if(!--in[nextt[now][i]]) q.push(nextt[now][i]);
		}
	}
	//for(int i=0;i<n;i++)
	//cout<<len[i]<<' ';
	//cout<<endl; 
	if(len[n] == -1e9) cout<<"-1"<<endl;
	else cout<<len[n];
	return 0;
}
  • 26
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值