#include <bits/stdc++.h>
#define bug1(x) cout<<#x<<" = "<<x<<endl
#define bug2(x,y) cout<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
#define bug3(x,y,z) cout<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<" "<<#z<<" = "<<z<<endl
#define bug4(x,y,z,m) cout<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<" "<<#z<<" = "<<z<<" "<<#m<<" = "<<m<<endl

using namespace std;

class Debugger {
public:
	template<typename T>
	void printVector(vector<T> const &vec, bool printSize=true){
		if(printSize){
			cout << vec.size() << endl;
		}
		for(auto &elem : vec){
			cout << elem << " ";
		}
		cout << endl;
	}

	template<typename T>
	void printMatrix(vector<vector<T>> const &matrix){
		cout << matrix.size()<< " ";
		if(!matrix.empty()){
			cout << matrix[0].size();
		}
		cout << endl; 
		for(auto &vec : matrix){
			printVector(vec, false);
		}
		cout << endl;
	}
};

#define ll long long
const ll INF = 1e18;
const int MAXN = 1000005;

struct Node {
	int index, type, size;
	bool operator<(const Node& other) const {
		return index < other.index;
	}
};


class TaskF {
private:
	Debugger debugger;
	vector<string> words;
	pair<pair<string, string>, bool> resolve(const string &le, const string &ri) {
		if(le.size() <= ri.size()) {
			string tmp = le;
			reverse(tmp.begin(), tmp.end());
			if(tmp == ri.substr(ri.size() - le.size())) {
				return { {"" ,ri.substr(0, ri.size() - le.size())}, true };
			} else {
				return {{"",""}, false};
			}
		} else {
			string tmp = ri;
			reverse(tmp.begin(), tmp.end());
			if(tmp == le.substr(0, tmp.size())) {
				return {{le.substr(tmp.size()), ""}, true};
			} else {
				return {{"",""}, false};
			}
		}
	}
	
	pair<Node, bool> check(Node &curr, int otherIndex) {
		int totalSize = words[curr.index].size();
		pair<pair<string,string>, bool> ans;
		if(curr.type == 0) {
			string w = words[curr.index].substr(totalSize-curr.size);
			ans = resolve(w, words[otherIndex]);
		} else {
			string w = words[curr.index].substr(0, curr.size);
			ans = resolve(words[otherIndex], w);
		}
		if(!ans.second) {
			return {curr, false};
		} else {
			if(!ans.first.first.empty()) {
				return {Node{curr.type == 0 ? curr.index : otherIndex,
				   	0, (int)ans.first.first.size()}, true};
			} else {
				return {Node{curr.type == 1 ? curr.index : otherIndex,
				   	1, (int)ans.first.second.size()}, true};
			}
		}
	}

	bool isPalindrome(const Node &curr) {
		string s;
		if(curr.type == 0) {
			int totalSize = words[curr.index].size();
			s = words[curr.index].substr(totalSize - curr.size);
		} else {
			s = words[curr.index].substr(0, curr.size);
		}
		string tmp = s;
		reverse(tmp.begin(), tmp.end());
		return tmp == s;
	}

public:
	void solveOne(int it){
		int n;
		cin >> n;
		words.resize(n);
		vector<int> cost(n);
		for(int i = 0; i < n; i++) {
			cin >> words[i] >> cost[i];
		}
		vector<vector<vector<ll>>> dist(n, vector<vector<ll>>(2, vector<ll>(22, INF)));
		priority_queue<pair<ll,Node>> PQ;
		for(int i = 0; i < n; i++) {
			int sz = words[i].size();
			PQ.push({-cost[i], Node{i, 0, sz}});
			dist[i][0][sz] = cost[i];
			PQ.push({-cost[i], Node{i, 1, sz}});
			dist[i][1][sz] = cost[i];
		}
		while(!PQ.empty()) {
			auto curr = PQ.top();
			PQ.pop();
			ll c = -curr.first;
			int index = curr.second.index;
			int type = curr.second.type;
			int size = curr.second.size;
			if(c != dist[index][type][size]) {
				continue;
			}
			if(isPalindrome(curr.second)) {
				cout << c << endl;
				return;
			}

			for(int i = 0; i < n; i++) {
				auto response = check(curr.second, i);
				if(!response.second) {
					continue;
				}
				auto newNode = response.first;
				if(c + cost[i] < dist[newNode.index][newNode.type][newNode.size]) {
					dist[newNode.index][newNode.type][newNode.size] = c + cost[i];
					PQ.push({-(c + cost[i]), newNode});
				}
			}
		}
		cout << -1 << endl;
	}

	void solve(){
		int tc = 1;
		for(int it = 1; it <= tc; it++){
			solveOne(it);
		}
	}
};


int main(){
	ios_base::sync_with_stdio(false);
	TaskF solver;
	solver.solve();
	return 0;
}


Measured memory_bytes: 3628