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 (GCC 5.4.1) (judge verdict: Accepted)

#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 内部定数
#define D_ON			1										// 汎用フラグ - ON
#define D_OFF			0										// 汎用フラグ - OFF
#define D_VTX_MAX		1000									// 最大頂点数
#define D_EDGE_MAX		2000									// 最大辺数

// 内部構造体 - 頂点情報
typedef struct Vtx {
	long long mlScore;											// スコア
	int miInf;													// 無限フラグ
} Vtx;

// 内部構造体 - 辺情報
typedef struct Edge {
	int miVFNo;													// 頂点 - 元 1～
	int miVTNo;													// 頂点 - 先 1～
	int miScore;												// スコア
} Edge;

// 内部変数
static Vtx sz1Vtx[D_VTX_MAX + 5];								// 頂点
static int siVCnt;												// 頂点数
static Edge sz1Edge[D_EDGE_MAX];								// 辺
static int siECnt;												// 辺数

// 内部変数 - テスト用
#ifdef D_TEST
	static int siRes;
	static FILE *szpFpT, *szpFpA;
#endif

// 頂点更新 - スコア・無限フラグ
int
fUpVtx(
	int piInf					// <I> 無限フラグの更新 [1]あり [0]なし
)
{
	int i, j;

	// 頂点のスコア - 更新(最大でも頂点数のループで更新が終了 - 頂点が１直線)
	for (i = 0; i < siVCnt; i++) {
		for (j = 0; j < siECnt; j++) {

			// 頂点(元)
			Vtx *lzpVtxF = &sz1Vtx[sz1Edge[j].miVFNo];

			// 接続有無
			if (lzpVtxF->mlScore == LLONG_MIN) {
				continue;
			}

			// スコア
			long long llSocre = lzpVtxF->mlScore + (long long)sz1Edge[j].miScore;

			// 頂点(先)
			Vtx *lzpVtxT = &sz1Vtx[sz1Edge[j].miVTNo];
			if (lzpVtxT->mlScore < llSocre) {
				lzpVtxT->mlScore = llSocre;

				if (piInf == D_ON) {
					lzpVtxT->miInf = D_ON;
				}
			}
		}
	}

	return 0;
}

// 実行メイン
int
fMain(
	int piTNo					// <I> テスト番号 1～
)
{
	int i;
	char lc1Buf[1024], lc1Out[1024];

	// データ初期化
	memset(sz1Vtx, 0, sizeof(sz1Vtx));							// 頂点

	// テストファイルオープン
#ifdef D_TEST
	sprintf(lc1Buf, ".\\Test\\T%d.txt", piTNo);
	szpFpT = fopen(lc1Buf, "r");
	sprintf(lc1Buf, ".\\Test\\A%d.txt", piTNo);
	szpFpA = fopen(lc1Buf, "r");
	siRes = 0;
#endif

	// 頂点数・辺数取得
#ifdef D_TEST
	fgets(lc1Buf, sizeof(lc1Buf), szpFpT);
#else
	fgets(lc1Buf, sizeof(lc1Buf), stdin);
#endif
	sscanf(lc1Buf, "%d%d", &siVCnt, &siECnt);

	// 辺取得
	for (i = 0; i < siECnt; i++) {
#ifdef D_TEST
		fgets(lc1Buf, sizeof(lc1Buf), szpFpT);
#else
		fgets(lc1Buf, sizeof(lc1Buf), stdin);
#endif
		sscanf(lc1Buf, "%d%d%d", &sz1Edge[i].miVFNo, &sz1Edge[i].miVTNo, &sz1Edge[i].miScore);
	}

	// 頂点のスコア - 初期化
	sz1Vtx[1].mlScore = 0;
	for (i = 2; i <= siVCnt; i++) {
		sz1Vtx[i].mlScore = LLONG_MIN;
	}

	// 頂点のスコア - 更新
	fUpVtx(D_OFF);

	// まだ更新できるかチェック(ループの有無チェック)
	fUpVtx(D_ON);

	// 結果セット
	if (sz1Vtx[siVCnt].miInf == D_ON) {
		sprintf(lc1Out, "inf\n");
	}
	else {
		sprintf(lc1Out, "%lld\n", sz1Vtx[siVCnt].mlScore);
	}

	// 結果表示
#ifdef D_TEST
	fgets(lc1Buf, sizeof(lc1Buf), szpFpA);
	if (strcmp(lc1Buf, lc1Out)) {
		siRes = -1;
	}
#else
	printf("%s", lc1Out);
#endif

	// テストファイルクローズ
#ifdef D_TEST
	fclose(szpFpT);
	fclose(szpFpA);
#endif

	// テスト結果
#ifdef D_TEST
	if (siRes == 0) {
		printf("OK %d\n", piTNo);
	}
	else {
		printf("NG %d\n", piTNo);
	}
#endif

	return 0;
}

int
main()
{

#ifdef D_TEST
	int i;
	for (i = D_TEST_SNO; i <= D_TEST_ENO; i++) {
		fMain(i);
	}
#else
	fMain(0);
#endif

	return 0;
}