#include <bits/stdc++.h>
using namespace std;
template<class T> ostream& operator<<(ostream &os, vector<T> V) { os << "[ "; 
  for(auto v:V)os << v << " "; return os << "]";
}
template<class T> ostream& operator<<(ostream &os, set<T> S){ os << "{ "; 
  for(auto s:S) os<<s<<" ";  return os<<"}"; 
}
template<class L, class R> ostream& operator<<(ostream &os, pair<L,R> P) {
  return os<<"("<<P.first<<","<< P.second << ")";
}
template<class L, class R> ostream& operator<<(ostream &os, map<L,R> M) {
  os<<"{ ";for(auto m:M)os<<"("<<m.first<<":"<<m.second<<")";
  return os<<"}";
}
#define cerr cout
#define TRACE
#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...) 1
#endif
// #include <ext/pb_ds/assoc_container.hpp> 
// #include <ext/pb_ds/tree_policy.hpp> 
// using namespace __gnu_pbds;
// #define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
// find_by_order(k)  returns iterator to kth element starting from 0;
// order_of_key(k) returns count of elements strictly smaller than k;
//For multiset use less_equal operator but it does support erase operations for multiset
#define ll long long
#define ld long double
#define vll vector<ll>
#define pll pair<ll,ll>
#define vpll vector<pll>
#define I insert 
#define pb push_back
#define F first
#define S second
#define endl "\n"
#define all(v) (v).begin(),(v).end()
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef pair<pii,int> ppi;
typedef vector<pii> vpii;
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define mp make_pair


const int mod = 1e9+7;

inline int add(int a,int b){a+=b;if(a>=mod)a-=mod; return a;} 
inline int sub(int a,int b){a-=b;if(a<0) a += mod; return a;}
inline int mul(int a, int b){ return a*1ll*b%mod;}
inline int power(int x, ll y){
  int res = 1;
  while(y){
    if(y&1) res = mul(res , x);
    x = mul(x,x);
    y >>= 1;
  }
  return res;
}

const int N = 55;
const int S = 22;
const ll INF = 1e18;
ll dis[2][N][S]; 
//0 is for prefix s is the length
//1 is for suffix lenght
//dp is over the minimums
string s[N];
ll C[N];

struct Node{
  bool flag;
  int id;
  int len;
  ll cost;

  Node(bool f, int i, int l, ll c){
    flag = f;
    id = i;
    len = l;
    cost = c;
  }
  bool operator < (const Node &rhs) const{
    return cost > rhs.cost;    
  }

};

int main(){
  fio; cout<<fixed<<setprecision(25);	
  int n; cin >> n;
  for(int i = 1;i <= n ; ++i){
    cin >> s[i] >> C[i];
  }
  for(int i = 0;i < N; ++i){
    for(int j = 0;j < S ; ++j)
      dis[0][i][j] = INF, dis[1][i][j] = INF;
  }
  priority_queue<Node> Q;

  for(int j =1 ;j <= n ; ++j){
    for(int i = 0;i <= s[j].size(); ++i){
      bool ok = true;
      int l = 0 , r = i-1;
      while(l <= r){
        if(s[j][l] != s[j][r]){
          ok = false;
          break;
        }
        ++l, --r;
      }
      if(ok){
        dis[1][j][s[j].size()-i] = C[j];
        Q.push(Node(1 , j , s[j].size()-i, C[j]));
      }
      ok = true;
      l = i, r = s[j].size()-1;
      while(l <= r){
        if(s[j][l] != s[j][r]){
          ok = false;
          break;
        }
        ++l, --r;
      }
      if(ok){
        dis[0][j][i] = C[j];
        Q.push(Node(0, j, i, C[j]));
      }
    }
    //reverse(all(s[j]));
  }

  while(Q.size()){
    Node t = Q.top();
    Q.pop();
    //cout << t.flag << ' ' << t.id << ' ' << t.len << ' ' << t.cost << endl;
    if(t.len == 0) continue;
    string tmp;
    if(t.flag) tmp = s[t.id].substr(s[t.id].size()-t.len);
    else tmp = s[t.id].substr(0 , t.len);
    string rtmp = tmp;
    reverse(all(rtmp));
    for(int i = 1;i <= n ; ++i){
      int kk = min( (int)tmp.size() , (int)s[i].size()); 
      string rs = s[i];
      reverse(all(rs));
      ll cost = t.cost + C[i];
      if(!t.flag){
        //currently its prefix
        //s[i] will become suffix
        if(tmp.size() >= s[i].size()){ 
          if(tmp.substr(tmp.size()-kk) == rs){
            if(dis[0][t.id][tmp.size()-kk] > cost){
              dis[0][t.id][tmp.size()-kk] = cost;
              //if(cost == 6) cout <<1 << ' ' << tmp << ' ' << s[i] << endl;
              Q.push(Node(0, t.id, tmp.size()-kk,cost)); 
            }
          }
        }
        else{
          if(s[i].substr(0,kk) == rtmp){
            if(dis[1][i][s[i].size()-kk] > cost){
              dis[1][i][s[i].size()-kk] = cost;
              //if(cost == 6) cout << tmp << ' ' << s[i] << endl;
              Q.push(Node(1, i, s[i].size()-kk, cost));
            }
          }
        }
      }
      else{
        //its suffix currently
        //will become prefix
        if(tmp.size() >= s[i].size()){
          if(tmp.substr(0,kk) == rs){
            if(dis[1][t.id][tmp.size()-kk] > cost){
              dis[1][t.id][tmp.size()-kk] = cost;
              //if(cost == 6) cout << 2 << ' ' << tmp << ' ' << s[i] << endl;
              Q.push(Node(1, t.id, tmp.size()-kk,cost)); 
            }
          }
        }
        else{
          if(s[i].substr(s[i].size()-kk) == rtmp){
            if(dis[0][i][s[i].size()-kk] > cost){
              dis[0][i][s[i].size()-kk] = cost;
              //if(cost == 6) cout << tmp << ' ' << s[i] << endl;
              Q.push(Node(0, i, s[i].size()-kk, cost));
            }
          }
        }
      }
    }
  }
  ll ans = INF;
  for(int i = 1;i <= n ; ++i){
    ans = min(ans , dis[0][i][0]);
    ans = min(ans , dis[1][i][0]);
  }
  if(ans == INF) cout << -1 << endl;
  else
  cout << ans << endl; 
  return 0;
}



Measured memory_bytes: 3672