// Original C++ solution (slower):
#include <iostream>

#include <algorithm>

#include <array>

#include <cstdint>

#include <functional>

#include <map>

#include <math.h>

#include <queue>

#include <set>

#include <stack>

#include <stdlib.h>

#include <string>

#include <time.h>

#include <utility>

#include <vector>



#define INF 1000000000

#define MOD 1000000007

#define rep(i,a,b) for(uint32 i = (a); i < (b); ++i)

#define bitget(a,b) (((a) >> (b)) & 1)

#define ALL(x) (x).begin(),(x).end()

#define C(x) std::cout << #x << " : " << x << std::endl

#define scanf scanf_s



using int32 = std::int_fast32_t;

using int64 = std::int_fast64_t;

using uint32 = std::uint_fast32_t;

using uint64 = std::uint_fast64_t;



struct edge {

	uint32 from, to;

	int64 cost;

};

#define N 1000

int main(void) {

	std::ios::sync_with_stdio(false);

	std::cin.tie(0);

	uint32 n, m;

	std::cin >> n >> m;

	std::vector<int64> d(n, -(1e18));

	std::vector<edge> es;

	uint32 a, b;

	int64 c;

	rep(i, 0, m) {

		std::cin >> a >> b >> c;

		--a, --b;

		es.push_back({ a,b,c });

	}

	d[0] = 0;

	bool ch[N] = {};

	rep(i, 0, n) {

		rep(j, 0, m) {

			edge e = es[j];

			if (d[e.to] < d[e.from] + e.cost) {

				d[e.to] = d[e.from] + e.cost;

				if (i == n - 1) {

					ch[e.to] = 1;

				}

			}

		}

	}

	rep(i, 0, n) {

		rep(j, 0, m) {

			edge e = es[j];

			ch[e.to] |= ch[e.from];

		}

	}

	if (ch[n - 1]) {

		std::cout << "inf";

	}

	else {

		std::cout << d[n - 1];

	}

	std::cout << "\n";

	return 0;

}

// Optimized solution to the same problem (faster):
//#define NDEBUG

#define _CRT_SECURE_NO_WARNINGS

#include <array>

#include <cstddef>

#include <cstdint>

#include <cstdio>

#include <limits>

#include <memory>

#include <string>

#include <type_traits>



template <class Integral> class Rirange;



template <class Integral = std::size_t> class irange {

public:

	using value_type = Integral;

	using reference = value_type &;

	using const_reference = const value_type &;

	class irangeitr {

		friend irange;

		value_type i;

		irangeitr(const value_type x) noexcept : i(x) {}



	public:

		void operator++() noexcept { ++i; }

		value_type &operator*() noexcept { return i; }

		const_reference operator*() const noexcept { return i; }

		bool operator!=(const irangeitr &x) const noexcept { return i < x.i; }

	};



private:

	const value_type f, l;



public:

	irange(const value_type first, const value_type last) noexcept

		: f(first), l(last) {}

	irangeitr begin() const noexcept { return irangeitr(f); }

	irangeitr end() const noexcept { return irangeitr(l); }

	Rirange<value_type> rev() const noexcept {

		return Rirange<value_type>(l - 1, f - 1);

	}

};

template <class Integral = std::size_t> class Rirange {

public:

	using value_type = Integral;

	using reference = value_type &;

	using const_reference = const value_type &;

	class Rirangeitr {

		friend Rirange;

		value_type i;

		Rirangeitr(const value_type x) noexcept : i(x) {}



	public:

		void operator++() noexcept { --i; }

		reference operator*() noexcept { return i; }

		const_reference operator*() const noexcept { return i; }

		bool operator!=(const Rirangeitr &x) const noexcept {

			return (!~x.i && ~i) || x.i < i;

		}

	};



private:

	const value_type f, l;



public:

	Rirange(const value_type x, const value_type y) noexcept : f(x), l(y) {}

	Rirangeitr begin() const noexcept { return Rirangeitr(f); }

	Rirangeitr end() const noexcept { return Rirangeitr(l); }

	irange<value_type> rev() const noexcept {

		return irange<value_type>(l + 1, f + 1);

	}

};



template <class T> bool maxi(T &a, const T &b) {

	if (b < a)

		return 0;

	a = b;

	return 1;

}

template <class T> bool mini(T &a, const T &b) {

	if (a < b)

		return 0;

	a = b;

	return 1;

}

template <class T> bool smaxi(T &a, const T &b) {

	if (a < b) {

		a = b;

		return 1;

	}

	return 0;

}

template <class T> bool smini(T &a, const T &b) {

	if (b < a) {

		a = b;

		return 1;

	}

	return 0;

}

struct customIO {

	int c;

	bool f;

	std::array<int, 30> buf;

	const std::array<int, 10> itoc;

	std::array<std::uint_least8_t, 256> ctoi_base;

	const std::uint_least8_t *const ctoi;

	void get_c() { c = fgetc(stdin); }

	void put_c(int x) { fputc(x, stdout); }

	bool vacant() { return c == ' ' || c == '\n'; }

	operator int() { return 0; }



	explicit customIO()

		: itoc({ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }),

		ctoi(std::addressof(ctoi_base[-static_cast<std::int_fast16_t>(

			std::numeric_limits<char>::min())])) {

		for (std::uint_least8_t i = 0; i < 10; ++i)

			ctoi_base[static_cast<int>("0123456789"[i]) -

			static_cast<std::int_fast16_t>(

				std::numeric_limits<char>::min())] = i;

	}

	// in



	void cueing() {

		while (get_c(), vacant())

			;

	}

	template <class T>

	auto operator>>(T &d) ->

		typename std::enable_if<std::is_signed<T>::value, customIO &>::type {

		d = 0;

		f = 0;

		cueing();

		if (c == '-')

			f = 1, get_c();

		do

			d = d * 10 + ctoi[c];

		while (get_c(), !vacant());

		if (f)

			d = -d;

		return *this;

	}

	template <class T>

	auto operator>>(T &d) ->

		typename std::enable_if<!std::is_signed<T>::value, customIO &>::type {

		d = 0;

		cueing();

		do

			d = d * 10 + ctoi[c];

		while (get_c(), !vacant());

		return *this;

	}

	customIO &operator>>(char &d) {

		cueing();

		d = c;

		return *this;

	}

	customIO &operator>>(double &d) {

		scanf("%lf", &d);

		return *this;

	}

	customIO &operator>>(std::string &d) {

		d.clear();

		cueing();

		do

			d.push_back(c);

		while (get_c(), !vacant());

		return *this;

	}

	template <class T> T input() {

		T d;

		*this >> d;

		return d;

	}



	// out



	template <class T>

	auto operator<<(T d) ->

		typename std::enable_if<std::is_signed<T>::value, customIO &>::type {

		c = 0;

		f = 0;

		if (d < static_cast<T>(0))

			f = 1, d = -d;

		while (d)

			buf[c++] = itoc[d % 10], d /= 10;

		if (!c)

			buf[c++] = itoc[0];

		if (f)

			put_c('-');

		while (c--)

			put_c(buf[c]);

		return *this;

	}

	template <class T>

	auto operator<<(T d) ->

		typename std::enable_if<!std::is_signed<T>::value, customIO &>::type {

		c = 0;

		while (d)

			buf[c++] = itoc[d % 10], d /= 10;

		if (!c)

			buf[c++] = itoc[0];

		while (c--)

			put_c(buf[c]);

		return *this;

	}

	customIO &operator<<(char d) {

		put_c(d);

		return *this;

	}

	customIO &operator<<(double d) {

		printf("%f", d);

		return *this;

	}

	customIO &operator<<(const std::string &d) {

		for (const auto e : d)

			put_c(e);

		return *this;

	}

	customIO &operator<<(const char *d) {

		while (*d != '\0')

			put_c(*(d++));

		return *this;

	}

	void endl() { put_c('\n'); }

	void space() { put_c(' '); }

} IO;



using int32 = std::int_fast32_t;

using int64 = std::int_fast64_t;

using uint32 = std::uint_fast32_t;

using uint64 = std::uint_fast64_t;

using intl32 = std::int_least32_t;

using intl64 = std::int_least64_t;

using uintl32 = std::uint_least32_t;

using uintl64 = std::uint_least64_t;



struct edge {

	uint32 from, to;

	int64 cost;

	edge(uint32 x, uint32 y, int64 z)noexcept :from(x), to(y), cost(z){}

};

#include<vector>

int main() {

	const auto n = IO.input<uint32>();

	const auto m = IO.input<uint32>();

	std::vector<edge> E;

	for (const auto i : irange<>(0, m)) {

		uint32 a, b;

		int64 c;

		IO >> a >> b >> c;

		E.emplace_back(a - 1, b - 1, -c);

	}

	std::vector<int64> d(n, INT64_MAX / 2);

	d[0] = 0;

	for (const auto i : irange<>(0, n)) {

		for (const auto &e : E) {

			smini(d[e.to], d[e.from] + e.cost);

		}

	}

	int64 ans = d[n - 1];

	for (const auto i : irange<>(0, n)) {

		for (const auto &e : E) {

			smini(d[e.to], d[e.from] + e.cost);

		}

	}

	if (ans == d[n - 1]) {

		IO << -ans;

	}

	else {

		IO << "inf";

	}

	IO.endl();

	return 0;

}

// Fastest known solution for this problem: