#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;

bool rev_ok(std::string_view l, std::string_view r)
{
    assert((l.size() <= r.size()));
    auto iter1 = l.begin(), iter1_end = l.end();
    auto iter2 = r.begin();
    while (iter1 != iter1_end) {
        if (*iter1 != *iter2) { return false; }
        ++iter1;
        ++iter2;
    }
    return true;
}


//ダイクストラ
int64_t Dijkstra()
{
    using P = std::pair<int64_t, std::pair<int, std::pair<int, size_t>>>;//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.first = r; top.second.second.first = i; top.second.second.second = l;
            }
        }
        if (top.first == INF) {
            break;
        }

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

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

        size_t l = 0;
        int r = (nowpos.first + 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 (rev_ok(nowS, targetS)) {
                    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 (rev_ok(targetS, nowS)) {
                    assert((nowpos.second.second + targetlen <= S[nowpos.first][nowpos.second.first].size()));
                    auto& nextC = C[nowpos.first][nowpos.second.first][nowpos.second.second + 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;

    int64_t res1 = INF;
    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: 3180