Problem:
Score : 400 points

Problem Statement

There is a directed graph with N vertices and M edges.
The i-th edge (1≤i≤M) points from vertex a_i to vertex b_i, and has a weight c_i.
We will play the following single-player game using this graph and a piece.

Initially, the piece is placed at vertex 1, and the score of the player is set to 0.
The player can move the piece as follows:

When the piece is placed at vertex a_i, move the piece along the i-th edge to vertex b_i. After this move, the score of the player is increased by c_i.

The player can end the game only when the piece is placed at vertex N.
The given graph guarantees that it is possible to traverse from vertex 1 to vertex N.

When the player acts optimally to maximize the score at the end of the game, what will the score be?
If it is possible to increase the score indefinitely, print inf.

Constraints

2≤N≤1000

1≤M≤min(N(N-1),2000)

1≤a_i,b_i≤N (1≤i≤M)

a_i≠b_i (1≤i≤M)

a_i≠a_j or b_i≠b_j (1≤i<j≤M)

-10^9≤c_i≤10^9 (1≤i≤M)

c_i is an integer.

In the given graph, there exists a path from vertex 1 to vertex N.

Input

Input is given from Standard Input in the following format:

N M
a_1 b_1 c_1
a_2 b_2 c_2
:
a_M b_M c_M

Output

Print the maximum possible score at the end of the game, if it is finite. If it is possible to increase the score indefinitely, print inf.

Sample Input 1

3 3
1 2 4
2 3 3
1 3 5

Sample Output 1

7

There are two ways to move the piece to vertex N=3:

vertex 1 → vertex 2 → vertex 3 : score 4+3=7

vertex 1 → vertex 3 : score 5

Thus, the maximum possible score at the end of the game is 7.

Sample Input 2

2 2
1 2 1
2 1 1

Sample Output 2

inf

It is possible to increase the score indefinitely by alternating between vertex 1 and 2.

Sample Input 3

6 5
1 2 -1000000000
2 3 -1000000000
3 4 -1000000000
4 5 -1000000000
5 6 -1000000000

Sample Output 3

-5000000000

Solution in C# (Mono-mcs 6.8.0.105) (judge verdict: Wrong Answer)

using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading.Tasks;

/*
・概要
Bellman-Ford法は、
重み付き有向グラフにおける単一始点の最短経路問題を解くアルゴリズム。
辺の重みに負数が存在する場合に主に使う。
（cf. 辺の重みが非負数ならば、ダイクストラ法の方が高速）

・使用法
	1. BellmanFordクラスのインスタンスを作成
	引数は、頂点数N、始点の番号source
	（e.g. BellmanFord graph = new BellmanFord(N,source);）

	2. 与えられた辺を追加
	引数は、始点、終点、重み
	（e.g. graph.AddEdge(start,goal,value);）

	3. BellmanFord法で最短距離を決定する
	（e.g. graph.SetDist();）

	4. 負の経路が存在するかを判定
	始点から到達可能な地点にある閉路だけを対象とする場合は、引数をtrueにする
	（e.g. bool found = graph.FindNegativeCircle(true);）

	5. （最短経路が見つかった場合）始点からの最短距離を取得する
	引数は、目的地のインデックス
	（e.g. long ans = graph.GetDist(N-1);）
	→そもそも到達不可能な場合、long.MaxValueを返す

・アルゴリズム（計算量は O (V * E)：Vは頂点の数、Eは辺の数）
ループを回して、各ノードへの最短距離を更新し続ける。

・詳細

*/

class Program
{
	//Main
	static void Main(string[] args)
	{
		//読み込む
		string[] S = Console.ReadLine().Split(' ');
		int N = int.Parse(S[0]);
		int M = int.Parse(S[1]);

		//1. BellmanFordクラスのインスタンスを作成
		//引数は、頂点数N、始点の番号source
		int source = 0;
		BellmanFord graph = new BellmanFord(N,source);

		//2. 与えられた辺を追加
		for(int i=0; i<M; i++){
				string[] line = Console.ReadLine().Split(' ');
				int a = int.Parse(line[0])-1;
				int b = int.Parse(line[1])-1;
				//この問題では最長距離を求めるので、重みの正負を逆転させる
				long c = long.Parse(line[2]) * -1;

				//辺を追加
				/*
				引数は、始点、終点、重み
				*/
				graph.AddEdge(a,b,c);
		}

		//3. BellmanFord法で最短距離を決定する
		graph.SetDist();

		//4. 負の経路が存在するかを判定
		/*
		引数はそれぞれ、
		bool 始点から到達可能な地点にある閉路だけを対象とするか、
		int 始点から終点goalに達するまでの道に、閉路があるか
		→終点に達するまでかどうか気にしない場合は、-1を入力すること
		*/
		//今回は、終点に達するまでに閉路があるかを探索
		bool found = graph.NegativeCircle(true,N-1);

		//出力
		//負の閉路が見つからなかった場合
		if(!found){
			//4. 始点からの最短距離を取得する
			//引数は、目的地のインデックス
			long ans = graph.GetDist(N-1);

			//始点から到達不可能な場合（この問題では有り得ない）
			if(ans == long.MaxValue){
				Console.WriteLine("impossible");
			}
			//その他の場合
			else{
				//この問題では正負を逆転したので、元に戻す
				ans = -1 * ans;
				Console.WriteLine(ans);
			}
		}
		//見つかった場合
		else{
			Console.WriteLine("inf");
		}
	}
}


//Bellman-Ford法を用いて、最短距離を求める為のクラス
class BellmanFord{
	//最短距離の初期化に使う変数
	/*
	大き過ぎると、オーバーフローして大小比較にバグが生じるので注意！！！！
	*/
	static readonly long inf = 10000000000000;

	//辺を保存する構造体
	public struct Edge
	{
		//始点
		public int Start;
		//終点
		public int Goal;
		//重み（負数もOK）
		public long Value;

		public Edge(int s, int g, long v){
			this.Start = s;
			this.Goal = g;
			this.Value = v;
		}
	}

	//辺を保存するリスト
	List<Edge> edgeList;
	//各頂点への最短距離を保存する配列
	long[] minDist;
	//始点から到着可能かを示すフラグ
	bool[] connected;
	//始点
	int source;
	//何らかの負の閉路が存在するか
	bool negativeCircle;
	//始点から到達可能な場所に、負の閉路が存在するか
	bool negativeCircleConnected;
	//始点を通じてある終点に向かうまでに、負の閉路が存在するか
	bool[] negativeCircleToGoal;
	//負の閉路を探索済みかを示す変数
	bool negativeSearched;

	//コンストラクタ
	/*
	引数は頂点数、始点の番号
	*/
	public BellmanFord(int vertex, int source){
		this.edgeList = new List<Edge>();
		this.source = source;

		//各頂点への最短距離をinfで初期化
		//但し、始点の場合には0とする
		this.minDist = new long[vertex];
		for(int i=0; i<vertex; i++){
			if(i == source){
				continue;
			}else{
				minDist[i] = inf;
			}
		}

		//始点から繋がっているかの配列を初期化
		this.connected = new bool[vertex];
		//始点はtrue
		this.connected[source] = true;

		//ある終点に向かうまでに、負の閉路が存在するか
		this.negativeCircleToGoal = new bool[vertex];
	}

	//辺を追加するメソッド
	/*
	引数は、始点、終点、重み
	*/
	public void AddEdge(int start, int goal, long value){
		Edge edge = new Edge(start, goal, value);
		//始点から繋がっていることを示す
		if(start == this.source || this.connected[start]){
			this.connected[goal] = true;
		}
		this.edgeList.Add(edge);
	}

	//Bellman-Ford法で、最短距離を求めるメソッド
	public void SetDist(){
		//頂点数と辺数
		int V = this.minDist.Length;
		int E = this.edgeList.Count();

		//ループで最小値を更新
		//各ノードへの到達最小値を更新し続ける
		for(int i=0; i<V; i++){
			for(int j=0; j<E; j++){
				//当該頂点の始点、終点、重み
				int start = edgeList[j].Start;
				int goal = edgeList[j].Goal;
				long value = edgeList[j].Value;

				//始点から繋がっていることを示す
				if(start == this.source || this.connected[start]){
					this.connected[goal] = true;
				}

				//最小値を更新できる場合（この辺を使った方が重みが少ない場合）
				if(this.minDist[goal] > this.minDist[start] + value){
					this.minDist[goal] = this.minDist[start] + value;
				}
			}
		}
	}

	//負の閉路の存在を判定する関数
	/*
	引数はそれぞれ、
	bool 始点から到達可能な地点にある閉路だけを対象とするか、
	int 始点から終点goalに達するまでの道に、閉路があるか
	→終点に達するまでかどうか気にしない場合は、-1を入力すること
	*/
	public bool NegativeCircle(bool onlyConnected, int goal){
		//まだ探索していない場合、探索
		if(!this.negativeSearched){
			this.FindNegativeCircle();
		}

		//終点を限定しない場合
		if(goal < 0){
			//終点から到達可能な点に限定する場合
			if(onlyConnected){
				return this.negativeCircleConnected;
			}
			//どこかに閉路があれば良い場合
			else{
				return this.negativeCircle;
			}
		}
		//終点を限定する場合
		else{
			return this.negativeCircleToGoal[goal];
		}
	}

	//負の閉路の存在を測定する関数
	void FindNegativeCircle(){
		for(int i=0; i<this.edgeList.Count(); i++){
			int start = edgeList[i].Start;
			int goal = edgeList[i].Goal;
			long value = edgeList[i].Value;
			//負の閉路があるかをチェック
			/*
			V * E回の探索を終えたにもかかわらず、依然として最短距離を更新できるということは、
			無限ループとなっている
			（startからgoalへの負の経路を通ることで、依然として距離を短縮できてしまう）
			*/
			if(this.minDist[start] + value < this.minDist[goal]){
				//負の経路あり
				this.negativeCircle = true;

				//始点から到達可能な場合
				if(connected[start]){
					this.negativeCircleConnected = true;
					//goalに到達するまでの負の経路あり
					this.negativeCircleToGoal[goal] = true;
				}
			}
		}

		this.negativeSearched = true;
	}

	//始点からの最短距離を出力
	public long GetDist(int goal){
		//始点から繋がっている場合、最短距離を返す
		if(this.connected[goal]){
			return this.minDist[goal];
		}
		//始点から到達不可能な場合、INFを返す
		else{
			return long.MaxValue;
		}
	}
}