#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,m,n) for(int i=(m);i<(n);++i)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) (v).begin(),(v).end()
using ll = long long;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3fLL;
const double EPS = 1e-8;
const int MOD = 1000000007;
// const int MOD = 998244353;
const int dy[] = {1, 0, -1, 0}, dx[] = {0, -1, 0, 1};
const int dy8[] = {1, 1, 0, -1, -1, -1, 0, 1}, dx8[] = {0, -1, -1, -1, 0, 1, 1, 1};
template <typename T, typename U> inline bool chmax(T &a, U b) { return a < b ? (a = b, true) : false; }
template <typename T, typename U> inline bool chmin(T &a, U b) { return a > b ? (a = b, true) : false; }
struct IOSetup {
  IOSetup() {
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(20);
  }
} iosetup;

using CostType = ll;
struct Edge {
  int src, dst; CostType cost;
  Edge(int src, int dst, CostType cost = 0) : src(src), dst(dst), cost(cost) {}
  inline bool operator<(const Edge &x) const {
    return cost != x.cost ? cost < x.cost : dst != x.dst ? dst < x.dst : src < x.src;
  }
  inline bool operator<=(const Edge &x) const { return !(x < *this); }
  inline bool operator>(const Edge &x) const { return x < *this; }
  inline bool operator>=(const Edge &x) const { return !(*this < x); }
};

struct Dijkstra {
  using Pci = pair<CostType, int>;

  Dijkstra(const vector<vector<Edge>> &graph, const CostType CINF) : graph(graph), CINF(CINF) {}

  vector<CostType> build(int s) {
    int n = graph.size();
    vector<CostType> dist(n, CINF);
    dist[s] = 0;
    prev.assign(n, -1);
    priority_queue<Pci, vector<Pci>, greater<Pci>> que;
    que.emplace(0, s);
    while (!que.empty()) {
      CostType cost; int ver; tie(cost, ver) = que.top(); que.pop();
      if (dist[ver] < cost) continue;
      for (const Edge &e : graph[ver]) {
        if (dist[e.dst] > dist[ver] + e.cost) {
          dist[e.dst] = dist[ver] + e.cost;
          prev[e.dst] = ver;
          que.emplace(dist[e.dst], e.dst);
        }
      }
    }
    return dist;
  }

  vector<int> build_path(int t) const {
    vector<int> res;
    for (; t != -1; t = prev[t]) res.emplace_back(t);
    reverse(ALL(res));
    return res;
  }

private:
  vector<vector<Edge>> graph;
  const CostType CINF;
  vector<int> prev;
};

struct Manacher {
  template <typename T>
  Manacher(const T &s) {
    T str;
    int n = s.size();
    REP(i, n) {
      str.push_back(s[i]);
      if (i + 1 < n) str.push_back('$');
    }
    n = str.size();
    radius.resize(n);
    int j = 1;
    for (int i = 0; i < n;) {
      while (i - j >= 0 && i + j < n && str[i - j] == str[i + j]) ++j;
      radius[i] = j;
      int k = 1;
      while (i - k >= 0 && i + k < n && k + radius[i - k] < j) {
        radius[i + k] = radius[i - k];
        ++k;
      }
      i += k;
      j -= k;
    }
  }

  int odd(int idx) const { return (radius[idx * 2] + 1) / 2; }

  int even(int idx) const { return radius[idx * 2 + 1] / 2; }

  bool is_palindrome(int left, int right) const {
    int mid = (left + right - 1) / 2;
    return (((right - left) & 1) ? odd(mid) * 2 - 1 : even(mid) * 2) >= right - left;
  }

private:
  vector<int> radius;
};

// ref. https://onlinejudge.u-aizu.ac.jp/problems/1406
int main() {
  const int L = 20;
  int n; cin >> n;
  vector<string> s(n);
  vector<int> c(n);
  REP(i, n) cin >> s[i] >> c[i];
  vector<vector<Edge>> graph(n * L * 2 + 2);
  const int S = n * L * 2, T = n * L * 2 + 1;
  REP(i, n) {
    graph[S].emplace_back(S, i * L, c[i]);
    int i_len = s[i].length();
    Manacher manacher(s[i]);
    REP(j, i_len) {
      if (manacher.is_palindrome(j, i_len)) graph[i * L + j].emplace_back(i * L + j, T, 0);
      if (manacher.is_palindrome(0, j + 1)) graph[n * L + i * L + j].emplace_back(n * L + i * L + j, T, 0);
    }
    REP(j, i_len) {
      int idx = i * L + j;
      REP(k, n) {
        int k_len = s[k].length(), i_pos = j, k_pos = k_len - 1;
        bool can_be_used = true;
        while (i_pos < i_len && k_pos >= 0) can_be_used &= s[i][i_pos++] == s[k][k_pos--];
        if (can_be_used) {
          if (i_pos == i_len && k_pos == -1) {
            graph[idx].emplace_back(idx, T, c[k]);
          } else if (i_pos == i_len) {
            graph[idx].emplace_back(idx, n * L + k * L + k_pos, c[k]);
          } else {  // k_pos == -1
            graph[idx].emplace_back(idx, i * L + i_pos, c[k]);
          }
        }
      }
    }
    REP(j, i_len) {
      int idx = n * L + i * L + j;
      REP(k, n) {
        int k_len = s[k].length(), i_pos = j, k_pos = 0;
        bool can_be_used = true;
        while (i_pos >= 0 && k_pos < k_len) can_be_used &= s[i][i_pos--] == s[k][k_pos++];
        if (can_be_used) {
          if (i_pos == -1 && k_pos == k_len) {
            graph[idx].emplace_back(idx, T, c[k]);
          } else if (i_pos == -1) {
            graph[idx].emplace_back(idx, k * L + k_pos, c[k]);
          } else {  // k_pos == k_len
            graph[idx].emplace_back(idx, n * L + i * L + i_pos, c[k]);
          }
        }
      }
    }
  }
  ll ans = Dijkstra(graph, LINF).build(S)[T];
  cout << (ans == LINF ? -1 : ans) << '\n';
  return 0;
}


Measured memory_bytes: 3796