use std::vec::Vec;

fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace().map(|e| e.parse().ok().unwrap()).collect()
}

fn main() {
    let (n, m) = {
        let v: Vec<usize> = read_vec();
        (v[0], v[1])
    };

    let mut edges = Vec::new();
    for _ in 0..m {
        let v: Vec<i64> = read_vec();
        edges.push((v[0] as usize - 1, v[1] as usize - 1, -v[2]));
    }

    match bellman_ford(&edges, n, 0, n-1) {
        Dist::Inf     => panic!("Error"),
        Dist::Fin(x)  => println!("{}", -x),
        Dist::Ninf    => println!("inf"),
    }
}

use std::fmt;

use std::cmp::Ordering;
use std::cmp::Ordering::Greater;
use std::cmp::Ordering::Less;
use std::cmp::Ordering::Equal;
use std::ops::Add;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Dist {
  Inf,
  Fin(i64),
  Ninf,
}

impl Dist {
    fn new(x: i64) -> Dist { Dist::Fin(x) }
}

impl Ord for Dist {
  fn cmp(&self, other: &Dist) -> Ordering {
    match (self, other) {
        (&Dist::Inf, &Dist::Inf) | (&Dist::Ninf, &Dist::Ninf) => Equal,
        (&Dist::Fin(x), &Dist::Fin(y))                        => x.cmp(&y),
        (&Dist::Inf, _) | (_, &Dist::Ninf)                    => Greater,
        (_, &Dist::Inf) | (&Dist::Ninf, _)                    => Less,
    }
  }
}

impl PartialOrd for Dist {
    fn partial_cmp(&self, other: &Dist) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Add for Dist {
  type Output = Self;
  fn add(self, other: Self) -> Self {
    match (self, other) {
      (Dist::Inf, Dist::Inf) | (Dist::Inf, Dist::Fin(_)) | (Dist::Fin(_), Dist::Inf)     => Dist::Inf,
      (Dist::Ninf, Dist::Ninf) | (Dist::Ninf, Dist::Fin(_)) | (Dist::Fin(_), Dist::Ninf) => Dist::Ninf,
      (Dist::Fin(x), Dist::Fin(y))                                                       => Dist::Fin(x + y),
      (Dist::Ninf, Dist::Inf) | (Dist::Inf, Dist::Ninf)                                  => panic!("not support INf + Ninf"),
    }
  }
}

impl fmt::Display for Dist {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self {
      &Dist::Inf    => write!(f, "Inf"),
      &Dist::Fin(x) => write!(f, "Fin({})", x),
      &Dist::Ninf   => write!(f, "Ninf"),
    }
  }
}

// start〜goalの最短経路を求める
// edges は (source, target, cost)のタプル
// 隣接リストじゃなくてもいい
// v: 頂点数
// O(VE)
fn bellman_ford(edges: &Vec<(usize, usize, i64)>, V: usize, start: usize, goal: usize) -> Dist {
    let mut dist = vec![Dist::Inf; V];
    let mut negative = vec![false; V];

    // init
    dist[start] = Dist::Fin(0);

    for _ in 0..V-1 {
        for &(source, target, cost) in edges {
            if dist[source] == Dist::Inf { continue }

            if dist[target] > dist[source] + Dist::new(cost)  && dist[source] != Dist::Inf {
               dist[target] = dist[source] + Dist::new(cost);
            }
        }
    }

  // 負閉路を検出する
  // グラフ全体として負閉路があるかではんく、start~goalまでの最短経路内で負閉路があるかを検出する
  for i in 0..V {
      for &(source, target, cost) in edges {
          if dist[source] == Dist::Inf { continue }

          if dist[target] > dist[source] + Dist::new(cost)  && dist[source] != Dist::Inf {
              dist[target] = Dist::Ninf;
              negative[target] = true;
          }

          if negative[source] == true {
             dist[target] = Dist::Ninf;
             negative[target] = true;
          }
      }
  }
    
    dist[goal]
}

Measured memory_bytes: 4352