#if 1
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack>
#include <array>
#include <deque>
#include <algorithm>
#include <utility>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <numeric>
#include <assert.h>
#include <bitset>
#include <list>
#include <cmath>

auto& in = std::cin;
auto& out = std::cout;
#define all_range(C) std::begin(C), std::end(C)
const double PI = 3.141592653589793238462643383279502884197169399375105820974944;


template<typename T, typename U>
std::enable_if_t<std::rank<T>::value == 0> fill_all(T& arr, const U& v) {
    arr = v;
}
template<typename ARR, typename U>
std::enable_if_t<std::rank<ARR>::value != 0> fill_all(ARR& arr, const U& v) {
    for (auto& i : arr) {
        fill_all(i, v);
    }
}

size_t N;
std::string S[2][50];
bool used[2][50][30];
int64_t C[2][50][30];
constexpr int64_t INF = 10000000000000000;

struct Pos {
    int r;//0で入力そのまま、1で逆順の文字列
    int i;
    size_t l;//S[r][i].substr(l)が中央の文字列
    bool operator<(const Pos&)const noexcept { return false; }//全部一致
};

//ダイクストラ
int64_t Dijkstra()
{
    using P = std::pair<int64_t, Pos>;//cost pos

    //初期化は入力時に行っているのでここではしない

    int64_t res = INF;
    for (;;)
    {
        //最短を見つける
        P top;
        top.first = INF;
        for (int r = 0; r <= 1; r++)
            for (int i = 0; i < N; i++)
                for (size_t l = 0; l <= S[r][i].size(); l++)
        {
            if (!used[r][i][l] && C[r][i][l] < top.first) {
                top.first = C[r][i][l];
                top.second.r = r; top.second.i = i; top.second.l = l;
            }
        }
        if (top.first == INF) {
            break;
        }

        const auto& nowpos = top.second;
        const auto& nowcost = top.first;
        const auto& nowS = std::string_view(S[nowpos.r][nowpos.i]).substr(nowpos.l);
        auto nowlen = nowS.size();

        used[nowpos.r][nowpos.i][nowpos.l] = true;
        if (std::equal(nowS.begin(), nowS.end(), nowS.rbegin(), nowS.rend())) {
            res = std::min(res, C[nowpos.r][nowpos.i][nowpos.l]);
            break;//枝刈り
        }

        size_t l = 0;
        int r = (nowpos.r + 1) % 2;
        for (int i = 0; i < N; i++)
        {
            const auto& targetS = std::string_view(S[r][i]).substr(l);
            auto targetlen = targetS.size();
            if (nowlen <= targetlen) {
                if (nowS == targetS.substr(0, nowS.size())) {
                    assert((l + nowlen <= S[r][i].size()));
                    C[r][i][l + nowlen] = std::min(C[r][i][l + nowlen], nowcost + C[r][i][l]);
                }
            }
            else {
                if (targetS == nowS.substr(0, targetS.size())) {
                    assert((nowpos.l + targetlen <= S[nowpos.r][nowpos.i].size()));
                    auto& nextC = C[nowpos.r][nowpos.i][nowpos.l + targetlen];
                    nextC = std::min(nextC, nowcost + C[r][i][l]);
                }
            }
        }
    }

    return res;
}



int main()
{
    using std::endl;
    in.sync_with_stdio(false);
    out.sync_with_stdio(false);
    in.tie(nullptr);
    out.tie(nullptr);
    fill_all(C, INF);
    in >> N;

    for (size_t i = 0; i < N; i++)
    {
        in >> S[0][i]; S[1][i] = S[0][i]; std::reverse(all_range(S[1][i]));
        in >> C[0][i][0]; C[1][i][0] = C[0][i][0];
    }

    auto res = Dijkstra();
    if (res == INF) {
        out << -1 << endl;
        return 0;
    }
    out << res << endl;
    return 0;
}
#endif


Measured memory_bytes: 3256