#include <bits/extc++.h>

#ifndef DUMP
#define DUMP(...) (void)0
#endif

using namespace std;

struct graph {
  struct edge {
    int src, dst, cost;
    int operator-(int v) const { return src ^ dst ^ v; }
  };
  int n, m;
  vector<edge> edges;
  vector<vector<pair<int, int>>> adj;
  graph(int _n = 0) : n(_n), m(0), adj(n) {}
  int add(const edge& e, bool directed = false) {
    edges.push_back(e);
    adj[e.src].emplace_back(m, e.dst);
    if (not directed) adj[e.dst].emplace_back(m, e.src);
    return m++;
  }
};

template <class T>
pair<vector<T>, vector<int>> dijkstra(const graph& g, int s) {
  vector d(g.n, numeric_limits<T>::max()), pe(g.n, -1);
  priority_queue<pair<T, int>, vector<pair<T, int>>, greater<>> pq;
  pq.emplace(d[s] = 0, s);
  while (not empty(pq)) {
    auto [dv, v] = pq.top();
    pq.pop();
    if (dv > d[v]) continue;
    for (auto [id, u] : g.adj[v])
      if (dv + g.edges[id].cost < d[u]) {
        d[u] = dv + g.edges[id].cost;
        pq.emplace(d[u], u);
        pe[u] = id;
      }
  }
  return {d, pe};
}

int main() {
  cin.tie(nullptr)->sync_with_stdio(false);
  int n;
  cin >> n;
  constexpr auto inf = numeric_limits<int64_t>::max();
  auto res = inf;
  vector<string> s, t, suff;
  vector<int> c;
  while (n--) {
    string si;
    cin >> si;
    int ci;
    cin >> ci;
    string ti(rbegin(si), rend(si));
    if (si == ti) {
      res = min<int64_t>(res, ci);
      continue;
    }
    s.push_back(si);
    t.push_back(ti);
    c.push_back(ci);
    int sz = size(si);
    for (int i = 0; i <= sz; ++i) {
      suff.push_back(si.substr(i));
      suff.push_back(ti.substr(i));
    }
  }
  n = size(s);
  if (n == 0) {
    cout << res << '\n';
    exit(0);
  }
  sort(begin(suff), end(suff));
  suff.erase(unique(begin(suff), end(suff)), end(suff));
  auto $ = [&](int tp, const string& rem) -> int {
    assert(binary_search(begin(suff), end(suff), rem));
    if (empty(rem)) return 0;
    if (tp == 0) {
      return lower_bound(begin(suff), end(suff), rem) - begin(suff);
    } else {
      return size(suff) +
             (lower_bound(begin(suff), end(suff), rem) - begin(suff));
    }
  };
  graph g(size(suff) * 2);
  for (auto&& rem : suff) {
    for (int i = 0; i < n; ++i) {
      if (binary_search(begin(suff), end(suff), rem + s[i])) {
        g.add({$(0, rem), $(0, rem + s[i]), c[i]}, true);
      }
      int len = min(size(rem), size(t[i]));
      if (rem.substr(0, len) != t[i].substr(0, len)) continue;
      if (size(t[i]) < size(rem)) {
        g.add({$(0, rem), $(0, rem.substr(len)), c[i]}, true);
      } else {
        g.add({$(0, rem), $(1, t[i].substr(len)), c[i]}, true);
      }
    }
  }
  for (auto&& rem : suff) {
    for (int i = 0; i < n; ++i) {
      if (binary_search(begin(suff), end(suff), rem + t[i])) {
        g.add({$(1, rem), $(1, rem + t[i]), c[i]}, true);
      }
      int len = min(size(rem), size(s[i]));
      if (rem.substr(0, len) != s[i].substr(0, len)) continue;
      if (size(s[i]) < size(rem)) {
        g.add({$(1, rem), $(1, rem.substr(len)), c[i]}, true);
      } else {
        g.add({$(1, rem), $(0, s[i].substr(len)), c[i]}, true);
      }
    }
  }
  DUMP(suff);
  for (int i = 0; i < n; ++i) {
    auto d = dijkstra<int64_t>(g, $(0, s[i])).first;
    auto x = d[$(0, t[i])];
    if (x == inf) continue;
    DUMP(x, i, s[i], c[i]);
    res = min(res, x / 2 + c[i]);
  }
  if (res == inf) res = -1;
  cout << res << '\n';
}


Measured memory_bytes: 3864