#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<cmath>
#include<functional>
#include<map>
#include<cstdlib>
#include<complex>
#include<numeric>
#include<set>
#include<deque>
#include<queue>

using namespace std;
using Int = long long;
Int INF = 1LL << 60;
const Int MOD = 1000000000 + 7;

template<Int Modulo = MOD> struct MInt {
	Int val;
	constexpr MInt(Int v = 0) noexcept : val(v% Modulo) {
		if (val < 0) v += Modulo;
	}
	constexpr Int getmod() { return Modulo; }
	constexpr MInt operator - () const noexcept { return val ? Modulo - val : 0; }
	constexpr MInt operator + (const MInt& r) const noexcept { return MInt(*this) += r; }
	constexpr MInt operator - (const MInt& r) const noexcept { return MInt(*this) -= r; }
	constexpr MInt operator * (const MInt& r) const noexcept { return MInt(*this) *= r; }
	constexpr MInt operator / (const MInt& r) const noexcept { return MInt(*this) /= r; }
	constexpr MInt& operator += (const MInt& r) noexcept {
		val += r.val;
		if (val >= Modulo) val -= Modulo;
		return *this;
	}
	constexpr MInt& operator -= (const MInt& r) noexcept {
		val -= r.val;
		if (val < 0) val += Modulo;
		return *this;
	}
	constexpr MInt& operator *= (const MInt& r) noexcept {
		val = val * r.val % Modulo;
		return *this;
	}
	constexpr MInt& operator /= (const MInt& r) noexcept {
		Int a = r.val, b = Modulo, u = 1, v = 0;
		while (b) {
			Int t = a / b;
			a -= t * b; swap(a, b);
			u -= t * v; swap(u, v);
		}
		val = val * u % Modulo;
		if (val < 0) val += Modulo;
		return *this;
	}
	constexpr bool operator == (const MInt& r) const noexcept {
		return this->val == r.val;
	}
	constexpr bool operator != (const MInt& r) const noexcept {
		return this->val != r.val;
	}
	friend ostream& operator << (ostream& os, const MInt<Modulo>& x) noexcept {
		return os << x.val;
	}
	friend istream& operator >> (istream& is, MInt<Modulo>& x) noexcept {
		Int tmp; is >> tmp;
		x = MInt<Modulo>(tmp);
		return is;
	}
	friend constexpr MInt<Modulo> modpow(const MInt<Modulo>& a, Int n) noexcept {
		MInt res(1), tmp = a;
		while (n > 0) {
			if (n & 1) res *= tmp;
			tmp *= tmp;
			n >>= 1;
		}
		return res;
	}
};

using mInt = MInt<>;

template<class T = Int>
struct Edge {
	Int from, to;
	T cost;
	Edge() {}
	Edge(Int from, Int to, T cost) : from(from), to(to), cost(cost) {}
};

template<class T>
vector<T> Bellman_Ford(vector<Edge<T>>& edges, Int V, Int st) {//V:ノード数 st:スタート地点

	const T inf = numeric_limits<T>::max(); // different from INF!!!
	vector<T> dist(V, inf);
	dist[st] = 0;
	for (Int i = 0; i < V - 1; i++) {
		for (const auto& e : edges) {
			if (dist[e.from] == inf) continue;//ないとオーバーフローの可能性あり、infの定義次第、つけとくのが無難、ただの枝切りではない
			dist[e.to] = min(dist[e.to], dist[e.from] + e.cost);
		}
	}

	//負閉路探索
	//V-1回目より後に更新があると負閉路が検出されて、そこから1番遠いノードに伝播するまでV-1回かかりうるので追加でV回のループが必要
	for (Int i = 0; i < V; i++) {
		for (const auto& e : edges) { 
			if (dist[e.from] == inf) continue;
			if (dist[e.from] == -inf) dist[e.to] = -inf; // src is nloop -> dst is nloop
			else if (dist[e.to] > dist[e.from] + e.cost) dist[e.to] = -inf; // chmin is possible -> nloop
		}
	}

	return dist;
}



int main() {

	cin.tie(nullptr);
	ios::sync_with_stdio(false);

	Int N, M;
	cin >> N >> M;

	Int a, b, c;
	vector<Edge<Int>> edge(M);
	for (Int i = 0; i < M; i++) {
		cin >> a >> b >> c;
		a--;
		b--;
		edge[i].from = a;
		edge[i].to = b;
		edge[i].cost = -c;
	}

	vector<Int> ans;
	ans =Bellman_Ford(edge, N, 0);

	if (ans[N - 1] == -numeric_limits<Int>::max()) {
		cout << "inf" << "\n";
	}
	else {
		cout << -ans[N - 1] << "\n";
	}

}

Measured memory_bytes: 384