#if !defined(__clang__) && defined(__GNUC__)
#include <bits/stdc++.h>
#else
#include <cstdlib>
#include <climits>
#include <iostream>
#include <cstdint>
#include <vector>
#include <string>
#include <complex>
#include <bitset>
#include <queue>
#include <deque>
#include <stack>
#include <utility>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <regex>
#endif //  !defined(__clang__) && defined(__GNUG__)
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/multi_array.hpp>
#include <boost/optional.hpp>
#include <boost/math/common_factor_rt.hpp>

using namespace std;

/// 距離つきグラフ
template<typename T, typename D, D nonval>
class Gr {
public:
    using edge = std::unordered_map<T, D>;
    using vertex_iterator = typename std::unordered_map<T, edge>::iterator;
    using vertex_const_iterator = typename std::unordered_map<T, edge>::const_iterator;

    Gr(T vertex_count, T edge_count) :
        vertex_count_(vertex_count), edge_count_(edge_count)
        {}

    // 値設定
    void set(T from, T to, D distance) {
        mat_[from][to] = distance;
    }

    // 距離
    D distance(T from, T to) const {
        if (mat_.find(from) != mat_.end()) {
            if (mat_[from].find(to) != mat_[from].end()) {
                return mat_[from][to];
            }
        }
        return nonval;
    }

    // 起点頂点をイテレート
    vertex_iterator from_vertex_begin() {
        return mat_.begin();
    }
    vertex_iterator from_vertex_end() {
        return mat_.end();
    }

    vertex_const_iterator from_vertex_cbegin() const {
        return mat_.begin();
    }

    vertex_const_iterator from_vertex_cend() const {
        return mat_.end();
    }

    // とある起点頂点からの辺をイテレート
    typename edge::iterator edge_begin(T from) {
        return mat_[from].begin();
    }
    typename edge::iterator edge_end(T from) {
        return mat_[from].end();
    }

    typename edge::const_iterator edge_cbegin(T from) const {
        return mat_.at(from).cbegin();
    }
    typename edge::const_iterator edge_cend(T from) const {
        return mat_.at(from).cend();
    }

    /** 木の場合の最短距離を計算する
        O(V+E)
    */
    std::vector<T> find_shortest_path_on_tree(T start) const {

        std::vector<T> depth(vertex_count_);

        auto f = [this, &depth](auto F, T v, T prev, D d) -> void {
            depth[v] = d;
            for (auto&& e = this->edge_cbegin(v); e != this->edge_cend(v); ++e) {
                const auto to = e->first;
                const auto cost = e->second;
                if (to != prev) { // 戻る道は省く
                    F(F, to, v, d + cost);
                }
            }
        };

        f(f, start, -1, 0);

        return depth;
    }

    /** 最短経路を計算する

        ベルマンフォード法 O(V*E)

        start を起点として、各頂点への最短距離の配列を返す。
        特に、loop_detect_goal を終点とした経路について、負の閉路があって
        距離が定まらない場合は、boost::none を返す。

        loop_detect_goal に関係のない経路に負の閉路がある場合に注意。

        @code
        int64_t N, M;
        std::cin >> N >> M;

        Gr<int64_t, int64_t, 0> g(N, M);
        for (size_t i = 0; i < M; ++i) {
        int64_t a, b, c;
        std::cin >> a >> b >> c;
        a--;
        b--;
        // 有向グラフの場合。無効グラフなら反対のg.set(b, a, c);も必要。
        g.set(a, b, c);
        }
        auto d = g.find_shortest_path(0, N-1);
        if (!d) {
        std::cout << "inf" << std::endl;
        }
        else {
        std::cout << (*d)[N-1] << std::endl;
        }
        @endcode
    */
    boost::optional<std::vector<T>> find_shortest_path(T start, T loop_detect_goal) const {
        constexpr T INF = std::numeric_limits<T>::max() / 2 + 1;
        std::vector<D> d(vertex_count_, INF);
        d[start] = 0;

        for (T i = 0; i < vertex_count_ * 2; ++i) {
            bool update = false;
            // 辺をイテレート
            for (auto&& f = from_vertex_cbegin();
                 f != from_vertex_cend();
                 ++f)
            {
                for (auto&& e = f->second.begin();
                     e != f->second.end();
                     ++e)
                {
                    const auto from = f->first;
                    const auto to = e->first;
                    const auto cost = e->second;
                    if (d[from] != INF && d[to] > d[from] + cost) {
                        d[to] = d[from] + cost;
                        update = true;

                        if (i >= vertex_count_ - 1 && to == loop_detect_goal) {
                            return boost::none;
                        }

                    }
                }
            }
            if (!update) {
                break;
            }
        }
        return d;
    }

private:
    T vertex_count_;
    T edge_count_;
    std::unordered_map<T, edge> mat_;
};

int main()
{
    int64_t N, M;
    std::cin >> N >> M;

    Gr<int64_t, int64_t, 0> g(N, M);

    for (decltype(M) i = 0; i < M; ++i) {
        int64_t a, b, c;
        std::cin >> a >> b >> c;
        a--;
        b--;
        c *= -1;
        g.set(a, b, c);
    }

    auto d = g.find_shortest_path(0, N-1);
    if (!d) {
        std::cout << "inf" << std::endl;
    }
    else {
        std::cout << (*d)[N-1] * -1 << std::endl;
    }

    return 0;
}


Measured memory_bytes: 384