#include <bits/stdc++.h>

using namespace std;

using ll = long long;

constexpr char newl = '\n';

struct State {
    int at;
    ll cost;
    //int prev;
    State(int at, ll cost/*, int prev*/) : at(at), cost(cost)/*, prev(prev)*/ {}
    bool operator>(const State& s) const {
        return cost > s.cost;
    }
};

struct Edge {
    int to;
    ll cost;
    Edge(int to, ll cost) : to(to), cost(cost) {}
};

using Graph = vector< vector<Edge> >; //隣接リスト

const ll INF = 1e18;
//const int NONE = -1;

//sは始点、mincは最短経路のコスト、prevsは最短経路をたどる際の前の頂点
void dijkstra(int s, const Graph& graph, vector<ll>& minc/*, vector<int>& prevs*/){
    minc.assign(graph.size(), INF);
    //prevs.assign(graph.size(), NONE);

    priority_queue<State, vector<State>, greater<State> > pq;
    pq.emplace(s, 0/*, NONE*/);
    minc[s] = 0;

    while(!pq.empty()) {
        State cur = pq.top();
        pq.pop();
        if (minc[cur.at] < cur.cost) continue;

        for(const Edge& e : graph[cur.at]) {
            ll cost = cur.cost + e.cost;
            if (minc[e.to] <= cost) continue;
            minc[e.to] = cost;
            //prevs[e.to] = cur.at;
            pq.emplace(e.to, cost/*, cur.at*/);
        }
    }
}

bool isPalindrome(const string& s) {
    int n = s.size();
    for (int i = 0; i < n; i++) {
        if (s[i] != s[n - 1 - i]) return false;
    }
    return true;
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    int n;
    cin >> n;

    vector<string> s(n);
    vector<ll> c(n);
    for (int i = 0; i < n; i++) {
        cin >> s[i] >> c[i];
    }

    // ids[is_suffix][i-th string][(prefix end or suffix begin) pos] = id
    vector< vector< vector<int> > > ids(2, vector< vector<int> >(n, vector<int>(20, -1)));
    int next_id = 1; // 回文完成のidを0にする
    // id を割り振る
    for (int i = 0; i < n; i++) {
        int sz = s[i].size();

        for (int j = 0; j < sz; j++) {
            ids[false][i][j] = next_id++;
            // cerr << "false " << i << " " << j << " " << ids[false][i][j] << newl;
            ids[true][i][j] = next_id++;
            // cerr << "true " << i << " " << j << " " << ids[true][i][j] << newl;
        }
    }

    // グラフの構築 （遷移を計算）
    int src = next_id;
    Graph g(src + 1);
    for (int i = 0; i < n; i++) {
        int sz = s[i].size();

        // for prefix
        {
            string tmp = "";
            for (int j = 0; j < sz; j++) {
                tmp += s[i][j];

                int cur = ids[false][i][j];
                if (isPalindrome(tmp)) {
                    g[cur].emplace_back(0, 0);
                    continue;
                }

                for (int k = 0; k < n; k++) {
                    int sz2 = s[k].size();
                    int lim = max(sz2, (int)tmp.size());
                    for (int l = 0; l <= lim; ++l) {
                        if (l >= tmp.size()) {
                            int nex = (sz2 == tmp.size() ? 0 : ids[true][k][tmp.size()]);
                            g[cur].emplace_back(nex, c[k]);
                            break;
                        } else if (l >= sz2) {
                            int nex = ids[false][i][tmp.size() - 1 - l];
                            g[cur].emplace_back(nex, c[k]);
                            break;                            
                        } else if (tmp[tmp.size() - 1 - l] != s[k][l]) {
                            break;
                        }
                    }
                }
            }
        }

        // for suffix
        {
            string tmp = "";
            for (int j = sz - 1; j >= 0; j--) {
                tmp = s[i][j] + tmp;

                int cur = ids[true][i][j];
                if (isPalindrome(tmp)) {
                    g[cur].emplace_back(0, 0);
                    continue;
                }

                for (int k = 0; k < n; k++) {
                    int sz2 = s[k].size();
                    int lim = max(sz2, (int)tmp.size());
                    for (int l = 0; l <= lim; ++l) {
                        if (l >= sz2) {
                            int nex = (tmp.size() == sz2 ? 0 : ids[true][i][j + l]);
                            g[cur].emplace_back(nex, c[k]);
                            break;
                        } else if (l >= tmp.size()) {
                            int nex = ids[false][k][sz2 - 1 - l];
                            g[cur].emplace_back(nex, c[k]);
                            break;
                        } else if (tmp[l] != s[k][sz2 - 1 - l]) {
                            break;
                        }
                    }
                }
            }
        }
    }

    for (int i = 0; i < n; i++) {
        int nex = ids[true][i][0];
        g[src].emplace_back(nex, c[i]);
    }

    /*
    for (int i = 0; i < g.size(); i++) {
        for (auto& e : g[i]) {
            cerr << i << " -> " << e.to << ": " << e.cost << newl;
        }
    }*/

    vector<ll> minc;
    dijkstra(src, g, minc);
    cout << (minc[0] >= INF ? -1 : minc[0]) << newl;

    return 0;
}

Measured memory_bytes: 3736