//#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
//#include <stack>
#include <cstring>
#include <cassert>

using namespace std;

#ifdef LOCAL_DEBUG
#include <local_debug.h>
#define DEBUG(...) DBG2::print(#__VA_ARGS__, __LINE__, __VA_ARGS__)
#else
#define DEBUG(...)
#endif

#define SZ(a) int((a).size())
#define REP(i,n) for(int i=0,_n=(n);i<_n;++i)
#define FOR(i,a,b) for(int i=(a),_b=(b);i<=_b;++i)

typedef long long llong;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<llong> VL;
typedef vector<VL> VVL;

#define MAXN 50
#define MAXL 20

int N;
string S[MAXN];
int C[MAXN];

int longest_match(string SL, string SR) {
   int len = 0;
   for (int l = 0, r = SZ(SR)-1;
        l < SZ(SL) && r >= 0 && SL[l] == SR[r];
        ++l, --r)
      ++len;
   return len;
}

int M[MAXN+1][MAXL+1][MAXN][MAXL+1];
bool is_palindrome[2][MAXN+1][MAXL+1];
void precompute() {
   REP(i, N) {
      int i_len = S[i].size();
      REP(i_idx, i_len) {
         REP(j, N) {
            int j_len = S[j].size();
            for (int j_idx = j_len-1; j_idx >= 0; --j_idx) {
               int mlen = longest_match( S[i].substr(i_idx),
                                        S[j].substr(0, j_idx+1) );
               M[i][i_idx][j][j_idx] = mlen;
            }
         }
      }
   }
   REP(i, N) {
      int i_len = S[i].size();
      REP(i_idx, i_len) {
         string sub = S[i].substr(i_idx);
         int mlen = longest_match( sub, sub );
         is_palindrome[1][i][i_idx] = mlen >= i_len - i_idx;
      }
      is_palindrome[1][i][i_len] = true;
      for (int i_idx = i_len-1; i_idx >= 0; --i_idx) {
         string sub = S[i].substr(0, i_idx+1);
         int mlen = longest_match( sub, sub );
         is_palindrome[0][i][i_len-1-i_idx] = mlen >= i_idx+1;
      }
      is_palindrome[0][i][i_len] = true;      
   }

}

struct State {
   int n, mlen;
   bool left;
   llong cost;
   bool operator<(const State& s) const {
      if (cost != s.cost)
         return cost > s.cost;
      if (mlen != s.mlen)
         return mlen < s.mlen;
      if (n != s.n)
         return n > s.n;
      return left < s.left;
   }
};

const llong INF = 4e18;

int main(int argc, char* argv[]) {
   ios_base::sync_with_stdio(false); 
   cin.tie(nullptr);

   cin >> N;
   REP(i, N)
      cin >> S[i] >> C[i];

   precompute();

   VVL D[2];
   D[0] = VVL(N+1, VL(MAXL+1, INF));
   D[1] = VVL(N+1, VL(MAXL+1, INF));
   priority_queue<State> pq;
   REP(i, N) {
      pq.push({i, 0, true, C[i]});
      D[1][i][0] = C[i];
      
   // pq.push({i, 0, false, C[i]});
   // D[0][i][0] = C[i];
   }

   while (!pq.empty()) {
      State cur = pq.top();
      pq.pop();

      llong cost = D[cur.left][cur.n][cur.mlen];
      DEBUG(cur.left, cur.n, cur.mlen, cur.cost, S[cur.n].size());

      if (cost < cur.cost)
         continue;

      if (is_palindrome[cur.left][cur.n][cur.mlen]) {
         cout << cost << '\n';
         return 0;
      }
      REP(j, N) {
         int mlen = cur.left ?
                      M[cur.n][cur.mlen][j][SZ(S[j])-1] :
                      M[j][0][cur.n][SZ(S[cur.n])-1-cur.mlen];

         if (mlen != SZ(S[j]) && cur.mlen + mlen != SZ(S[cur.n]))
            continue;

         State nxt = mlen == SZ(S[j]) ?
                     State {cur.n, cur.mlen + mlen, cur.left, cost + C[j]} :
                     State {j, mlen, !cur.left, cost + C[j]};

         if (D[nxt.left][nxt.n][nxt.mlen] > nxt.cost) {
            D[nxt.left][nxt.n][nxt.mlen] = nxt.cost;
            pq.push(nxt);
         }
      }
   }

   cout << -1 << '\n';

   return 0;
}


Measured memory_bytes: 7932