// property

pub trait Property: Copy {}

impl<P> Property for P where P: Copy {}

pub trait Weighted: Property + std::ops::Add<Output=Self> + std::cmp::Ord{}

impl<W> Weighted for W where W: Property + std::ops::Add<Output=W> + std::cmp::Ord{}

pub trait NonNegativeWeighted: Weighted {}

impl NonNegativeWeighted for usize {}

//graph

use std::slice::Iter;

#[derive(Clone,Eq,PartialEq,Debug)]
pub struct Vertex(pub usize);

#[derive(Clone,Eq,PartialEq,Debug)]
pub struct Edge {
    pub index : usize,
    pub to : Vertex
}

pub trait Graph {
    type VP;
    type EP;
    fn new(n : usize , vp_init : Self::VP) -> Self;
    fn vertices_cnt(&self) -> usize;
    fn edges_cnt(&self) -> usize;
    fn add_edge(&mut self , from : &Vertex , to : &Vertex , edge_prop : Self::EP);
    fn delta(&self , v : &Vertex) -> Iter<Edge>;
    fn vprop_mut(&mut self, v : &Vertex) -> &mut Self::VP;
    fn vprop(&self, v : &Vertex) -> &Self::VP;
    fn eprop_mut(&mut self, e : &Edge) -> &mut Self::EP;
    fn eprop(&self, e : &Edge) -> &Self::EP;
}

pub struct DirectedGraph<VP: Property,EP: Property> {
    n : usize,
    m : usize,
    g : Vec<Vec<Edge>>,
    es : Vec<EP>,
    vs : Vec<VP>
}

pub struct UndirectedGraph<VP: Property,EP: Property> {
    n : usize,
    m : usize,
    g : Vec<Vec<Edge>>,
    es : Vec<EP>,
    vs : Vec<VP>
}

//directedgraph

impl<VP : Property ,EP : Property> Graph for DirectedGraph<VP,EP> {
    type VP = VP;
    type EP = EP;
    fn new(n : usize , vp_init: VP) -> Self {
        DirectedGraph {
            n: n,
            m: 0,
            g: vec![Vec::<Edge>::new(); n],
            es: Vec::<EP>::new(),
            vs: vec![vp_init; n]
        }
    }
    fn add_edge(&mut self , from : &Vertex , to : &Vertex , edge_prop : Self::EP) {
        self.g[from.0].push(Edge{index : self.m , to : to.clone()});
        self.es.push(edge_prop);
        self.m += 1;
    }
    fn vertices_cnt(&self) -> usize { self.n }
    fn edges_cnt(&self) -> usize { self.m }
    fn delta(&self , v : &Vertex) -> Iter<Edge> {
        self.g[v.0].iter()
    }
    fn vprop_mut(&mut self, v : &Vertex) -> &mut Self::VP {
        &mut self.vs[v.0]
    }
    fn vprop(&self, v : &Vertex) -> &Self::VP {
        & self.vs[v.0]
    }
    fn eprop_mut(&mut self, e : &Edge) -> &mut Self::EP {
        &mut self.es[e.index]
    }
    fn eprop(&self, e : &Edge) -> &Self::EP {
        & self.es[e.index]
    }
}

#[derive(Clone,Copy,PartialEq,Eq)]
pub enum BFResult<W> {
    Some(W),
    NegInf,
    None
}

pub fn bellman_ford<VP,EP,W,F>(g: &DirectedGraph<VP,EP>, s: Vertex, start_prop: W, fp: F) -> Vec<BFResult<W>>
where VP: Property, EP: Property, W: Weighted, F: Fn(&EP) -> &W {
    let n = g.vertices_cnt();
    let mut dist = vec![BFResult::None ; n];
    dist[s.0] = BFResult::Some(start_prop);
    
    for i in 0..n+1 {
        for v in 0..n {
            if let BFResult::Some(dv) = dist[v] {
                for e in g.delta(&Vertex(v)) {
                    dist[e.to.0] = match dist[e.to.0] {
                        BFResult::Some(dt) => {
                            if dv + *fp(g.eprop(e)) < dt {
                                BFResult::Some(dv + *fp(g.eprop(e)))
                            }
                            else {
                                BFResult::Some(dt)
                            }
                        }
                        BFResult::None => {
                            BFResult::Some(dv + *fp(g.eprop(e)))
                        }
                        _ => {
                            BFResult::None
                        }
                    }
                }
            }
        }
    }
    for i in 0..n+1 {
        for v in 0..n {
            if let BFResult::Some(dv) = dist[v] {
                for e in g.delta(&Vertex(v)) {
                    dist[e.to.0] = match dist[e.to.0] {
                        BFResult::Some(dt) => {
                            if dv + *fp(g.eprop(e)) < dt {
                                BFResult::NegInf
                            }
                            else {
                                BFResult::Some(dt)
                            }
                        }
                        BFResult::None => {
                            BFResult::Some(dv + *fp(g.eprop(e)))
                        }
                        BFResult::NegInf => {
                            BFResult::NegInf
                        }
                    }
                }
            }
            else if let BFResult::NegInf = dist[v] {
                for e in g.delta(&Vertex(v)) {
                    dist[e.to.0] = BFResult::NegInf;
                }
            }
        }
    }

    dist
}

fn main() {
	let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let v:Vec<usize> = s.trim().split_whitespace()
        .map(|e|e.parse().unwrap()).collect();
    let (n,m) = (v[0] , v[1]);
	let mut g = DirectedGraph::<i64, i64>::new(n,0);
    for _ in 0..m{
        let mut t = String::new();
        std::io::stdin().read_line(&mut t).unwrap();
        let x:Vec<i64> = t.trim().split_whitespace()
            .map(|e|e.parse().unwrap()).collect();
        let (v,u,d) = (x[0],x[1],x[2]);
        g.add_edge(&Vertex(v as usize - 1),&Vertex(u as usize - 1),-d);
    }
	let res = bellman_ford(&g, Vertex(0), 0, |ep| ep);
    match res[n - 1] {
        BFResult::Some(i) => println!("{}",-i),
        _ => println!("inf")
    }
}


Measured memory_bytes: 4352