#line 1 "/workspaces/compro/lib/graph/edge.hpp"


template <typename T> struct edge {
  int to;
  T cost;
};

#line 2 "/workspaces/compro/lib/graph/dijkstra.hpp"
#include <climits>
#include <limits>
#include <queue>
#include <vector>

#ifndef DIJKSTRA
#define DIJKSTRA

// sからの各頂点への最短距離を返す。計算量はO(E logV)
template <class T> std::vector<T> dijkstra(const int s, const std::vector<std::vector<edge<T>>> &g) {
  std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>, std::greater<std::pair<T, int>>> q;

  constexpr T MAX = std::numeric_limits<T>::max();
  std::vector<T> d(g.size(), MAX);
  d[s] = 0;
  q.push(std::make_pair(d[s], s));

  while (!q.empty()) {
    const auto p = q.top();
    q.pop();

    const int v = p.second;
    if (d[v] < p.first)
      continue;

    for (const auto e : g[v]) {
      const int u = e.to;
      const T next_cost = d[v] + e.cost;
      if (d[u] <= next_cost)
        continue;
      d[u] = next_cost;
      q.push(std::make_pair(d[u], u));
    }
  }
  return d;
}

#endif
#line 1 "/workspaces/compro/lib/template.hpp"


#line 1 "/workspaces/compro/lib/io/vector.hpp"
#include <iostream>
#line 3 "/workspaces/compro/lib/io/vector.hpp"

#ifndef IO_VECTOR
#define IO_VECTOR

template <class T> std::ostream &operator<<(std::ostream &out, const std::vector<T> &v) {
  int size = v.size();
  for (int i = 0; i < size; i++) {
    std::cout << v[i];
    if (i != size - 1)
      std::cout << " ";
  }
  return out;
}

template <class T> std::istream &operator>>(std::istream &in, std::vector<T> &v) {
  for (auto &el : v) {
    std::cin >> el;
  }
  return in;
}

#endif
#line 4 "/workspaces/compro/lib/template.hpp"
#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; i < n; i++)
#define FOR(i, m, n) for (int i = m; i < n; i++)
#define ALL(v) (v).begin(), (v).end()
#define coutd(n) cout << fixed << setprecision(n)
#define ll long long int
#define vl vector<ll>
#define vi vector<int>
#define MM << " " <<

using namespace std;

template <class T> void say(bool val, T yes, T no) { cout << (val ? yes : no) << "\n"; }

void say(bool val, string yes = "Yes", string no = "No") { say<string>(val, yes, no); }

template <class T> void chmin(T &a, T b) {
  if (a > b)
    a = b;
}

template <class T> void chmax(T &a, T b) {
  if (a < b)
    a = b;
}

// C++ 17に完全移行したら消す
// 最大公約数を求める
template <class T> T gcd(T n, T m) { return n ? gcd(m % n, n) : m; }

// 最小公倍数を求める
template <class T> T lcm(T n, T m) {
  int g = gcd(n, m);
  return n * m / g;
}

// 重複を消す。計算量はO(NlogN)
template <class T> void unique(std::vector<T> &v) {
  std::sort(v.begin(), v.end());
  v.erase(std::unique(v.begin(), v.end()), v.end());
}


#line 3 "main.cpp"

bool isPa(string &s) {
  int i = 0, j = s.length() - 1;
  while (i < j) {
    if (s[i] != s[j])
      return false;
  }
  return true;
}

long long solve(int N, const std::vector<std::string> &S, const std::vector<long long> &C) {
  // prefixとsuffixからなる頂点を作成、どっちに属しているかを識別するためにmap<pair<string,int>,int>でindexを持つ
  map<pair<string, int>, int> mp; // prefixならsecondが0、suffixなら1
  mp[{"", 0}] = 0;
  mp[{"", 1}] = 1;

  vector<string> revS(N);
  REP(i, N) { revS[i] = string(S[i].rbegin(), S[i].rend()); }

  int idx_cnt = 2;
  auto add_substr = [&idx_cnt](string str, map<pair<string, int>, int> &mp, bool is_suffix) -> void {
    int len = str.length();
    REP(i, len + 1) {
      pair<string, int> target = {(is_suffix ? str.substr(i) : str.substr(0, i)), is_suffix};
      if (mp.count(target)) {
        continue;
      }
      mp[target] = idx_cnt;
      idx_cnt++;
    }
  };

  REP(i, N) {
    add_substr(S[i], mp, false);
    add_substr(S[i], mp, true);
  }

  int size = mp.size();
  vector<vector<edge<ll>>> g(size + 1);

  // 辺を張る。その文字列を適用したらどうなるのかを考えながら頑張る
  for (const auto &[p, idx] : mp) {
    const auto [str, isSuffix] = p;
    if (str == "")
      continue;
    REP(i, N) {
      int mini = min(str.length(), S[i].length());
      int maxi = max(str.length(), S[i].length());
      if (isSuffix) {
        if (str.substr(0, mini) != revS[i].substr(0, mini))
          continue;

        if (str.length() > S[i].length()) {
          g[idx].push_back({mp[{str.substr(mini), 1}], C[i]});
        } else {
          g[idx].push_back({mp[{S[i].substr(0, maxi - mini), 0}], C[i]});
        }
      } else {
        string rev = string(str.rbegin(), str.rend());
        if (rev.substr(0, mini) != S[i].substr(0, mini))
          continue;

        if (str.length() > S[i].length()) {
          g[idx].push_back({mp[{str.substr(0, maxi - mini), 0}], C[i]});
        } else {
          g[idx].push_back({mp[{S[i].substr(mini), 1}], C[i]});
        }
      }
    }
  }

  // 空文字列や回文の状態からゴール状態に遷移する辺を追加する。
  for (const auto &[p, idx] : mp) {
    const auto &[str, isSuffix] = p;
    string rev = string(str.rbegin(), str.rend());
    if (rev == str) {
      g[idx].push_back({size, 0});
    }
  }

  // 各文字列を先頭に使ったとしてdijkstraをN回チェック。
  ll ans = 1e18;
  REP(i, N) {
    auto d = dijkstra(mp[{S[i], 0}], g);
    if (d[size] != numeric_limits<ll>::max())
      chmin(ans, d[size] + C[i]);
  }

  // ゴール頂点までの距離が答え。
  return ans == 1e18 ? -1 : ans;
}

// generated by online-judge-template-generator v4.4.0 (https://github.com/kmyk/online-judge-template-generator)
int main() {
  int N;
  std::cin >> N;
  std::vector<string> S(N);
  std::vector<long long> C(N);
  for (int i = 0; i < N; ++i) {
    std::cin >> S[i] >> C[i];
  }
  auto ans = solve(N, S, C);
  std::cout << ans << std::endl;
  return 0;
}


Measured memory_bytes: 3884