// Original C++ solution (slower):
#include <bits/stdc++.h>



using namespace std;



#define EACH(i,a) for (auto& i : a)

#define FOR(i,a,b) for(int i=(int)a;i<(int)b;++i)

#define RFOR(i,a,b) for(int i=(int)b-1;i>=(int)a;--i)

#define REP(i,n) FOR(i,0,n)

#define RREP(i,n) RFOR(i,0,n)

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

#define debug(x) cerr << #x << ":" << x << endl;

#define OK(ok) cout << (ok ? "Yes" : "No") << endl;

typedef long long ll;



void CINT(){}

template <class Head,class... Tail>

void CINT(Head&& head,Tail&&... tail) {

  cin >> head; CINT(move(tail)...);

}

#define CIN(...) int __VA_ARGS__;CINT(__VA_ARGS__)

#define LCIN(...) ll __VA_ARGS__;CINT(__VA_ARGS__)

#define SCIN(...) string __VA_ARGS__;CINT(__VA_ARGS__)



const int INF = 1e9 + 1;

const ll LINF = 1e18 + 1;

const int MOD = 1e9 + 7;

const int MAX_N = 1e5 + 1;



int N, M;



struct Edge {

  Edge(int _from, int _to, ll _cost)

    : from(_from), to(_to), cost(_cost) {}

  int from;

  int to;

  ll cost;

};



vector< Edge > e;

ll d[MAX_N];

// bool state[MAX_N];



int main()

{

  cin.tie(0);

  ios::sync_with_stdio(false);



  fill_n(d, MAX_N, LINF);



  cin >> N >> M;

  vector< int > a(M);

  vector< int > b(M);

  vector< ll > c(M);

  REP(i, M) {

    cin >> a[i] >> b[i] >> c[i];

    a[i]--; b[i]--;

    e.emplace_back(Edge(a[i], b[i], -1ll * c[i]));

  }



  d[0] = 0ll;

  // state[0] = true;

  

  REP(i, N) {

    

    EACH(ei, e) {

      // if (!state[ei.from]) continue;

      if (d[ei.from] != LINF && d[ei.to] > d[ei.from] + ei.cost) {

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

	// state[ei.to] = true;

	

	if (i == N - 1 && ei.to == N - 1) {

	  cout << "inf" << endl;

	  return 0;

	}

      }

    }

  }



  

  ll ans = -1ll * d[N - 1];

  cout << ans << endl;



  /*

  REP(i, N) {

    debug(d[i]);

  }

  */

  

  return 0;

}




// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

// statics

using namespace std;

using int64 = long long;

using PAIR = pair<int, int>;

constexpr int INF = 1 << 30;

constexpr int64 LINF = 1LL << 60;

constexpr int MOD = 1e9 + 7;

constexpr int MAX_N = 1e5 + 1;



// init/input

#define int int64

#define INIT ios::sync_with_stdio(false);cin.tie(0);

#define VAR(type, ...) type __VA_ARGS__;MACRO_VAR_Scan(__VA_ARGS__);

template<typename T> void MACRO_VAR_Scan(T &t) {cin>>t;}

template<typename First, typename...Rest> void MACRO_VAR_Scan(First &first, Rest&...rest) {cin>>first;MACRO_VAR_Scan(rest...);}

#define VEC(type, c, n) vector<type> c(n);for(auto &&i:c)cin>>i;



// out

#define OUT(dist) cout<<(dist);

#define FOUT(n, dist) cout<<fixed<<setprecision(n)<<(dist);

#define SP cout<<" ";

#define BR cout<<"\n";

#define debug(x) cerr << #x << ":" << (x);BR;



// utility

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

#define EACH(i, a) for(auto &&i:(a))

#define FOR(i, a, b) for(int i=(a);i<(b);++i)

#define RFOR(i, a, b) for(int i=(b)-1;i>=0;--i)

#define REP(i, n) for(int i=0;i<(n);++i)

#define RREP(i, n) for(int i=(n)-1;i>=0;--i)



struct Edge {

	int from;

	int to;

	int cost;

};



vector< Edge > e;

int d[MAX_N];



signed main() {

  INIT;

	VAR(int, n, m);

	REP(i, m) {

		VAR(int, a, b, c);

		a--; b--;

		e.push_back(Edge{a, b, -c});

	}

	fill(d, d + n, LINF);



	d[0] = 0;

	REP(i, n) {

		EACH(t, e) {

			if (d[t.from] != LINF && d[t.to] > d[t.from] + t.cost) {

				// 更新できる時は更新

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



				if (i == n - 1 && t.to == n - 1) {

					// 閉路ができちゃってるとき

					OUT("inf")BR;

					return 0;

				}

			}

		}

	}

	int ans = -d[n - 1];

	OUT(ans)BR;

  

  return 0;

}


// Fastest known solution for this problem: