#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
using iPair = pair<int,int>;
using lPair = pair<ll, ll>;
using ivector = vector<int>;
using lvector = vector<ll>;
using istack = stack<int>;
using iqueue = queue<int>;
using ivv = vector<vector<int>>;
using lvv = vector<vector<ll>>;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
vector<iPair> dir = {{1,0}, {-1,0}, {0,1}, {0,-1}};
#define dump(x) cout << #x << " = " << (x) << endl
#define ALL(x) begin(x),end(x)
#define rep(i,s,e) for(ll i=(s); i<(ll)(e); ++i)
#define repRev(i,s,e) for(ll i=(e-1); i>=(ll)(s); --i)
#define range(i,s,n) for(ll i=(s), i_stop=(s)+(n); i<i_stop; ++i)
#define rangeRev(i,s,n) for(ll i=(s), i_stop=(s)-(n); i>i_stop; --i)
#define foreach(x,container) for(auto &&x:container)
bool chmax(ll& a, ll b) {if(a<b) {a=b;return true;} return false;}
bool chmin(ll& a, ll b) {if(a>b) {a=b;return true;} return false;}
template<typename T> void printArr(vector<T> &arr){
    for(auto &&x:arr) {cout << x << " ";} cout << endl;
}


/*
https://atcoder.jp/contests/abc184/tasks/abc184_e

## 關鍵詞：
圖論，最短路，BFS，Dijkstra，優化邊數，01BFS

## 題意：
給一副地圖，高H寬W。0 <= H,W <= 2e3。
若某個格子標記這小寫字母，代表該格子遷移到其他標記同樣字母的格子的費用是0。
求S到G的最短距離。

## 思路：
|V| <= 4e6, |E| <= |V|^2/2 = 8e12, TLE。
顯然直接建邊的話不可通過。
想用上次拿到題的思路，分兩層建邊，但是寫道一半就感覺非常麻煩。
做應該還是可以做的。

https://atcoder.jp/contests/abc184/editorial/352
題解的思路使用BFS。O(HW)復雜度。

## 雜多：


*/



void solve(){
    int h, w; cin >> h >> w;
    vector<string> grid(h+1);
    range(i, 0, h) cin >> grid[i];

    // 讀取S，G坐標
    // 讀取各個傳送點坐標
    int sy, sx, gy, gx;
    map<char, vector<iPair>> mapping;
    range(i, 0, h) range(j, 0, w) {
        if(grid[i][j] == 'S') {sy = i; sx = j; continue;}
        if(grid[i][j] == 'G') {gy = i; gx = j; continue;}
        char teleport = grid[i][j];
        if(teleport >= 'a' && teleport <= 'z') {
            mapping[teleport].emplace_back(i, j);
        }
    }

    // BFS遍歷全圖
    vector<vector<bool>> visited(h+1, vector<bool>(w+1, false));
    vector<lvector> dist(h+1, lvector(w+1, LINF));
    vector<bool> flag(30, false);
    queue<iPair> q;
    dist[sy][sx] = 0; q.emplace(sy, sx); visited[sy][sx] = true;
    ll ans = -1;
    while(q.size()) {
        auto [r, c] = q.front(); q.pop();
        ll d = dist[r][c];
        if(r==gy && c==gx) {
            ans = d;
            break;
        }

        // 向四周遍歷
        foreach(dir_item, dir) {
            auto [dy, dx] = dir_item;
            int rr = r+dy;
            int cc = c+dx;
            if(rr<0 || rr>=h) continue;
            if(cc<0 || cc>=w) continue;
            if(grid[rr][cc] == '#') continue;
            if(visited[rr][cc]) continue;
            visited[rr][cc] = true;

            if(chmin(dist[rr][cc], d+1)) q.emplace(rr, cc);
        }

        // 如果這個傳送點沒被用過，那麼將所有相連的傳送點也加入隊列
        char teleport = grid[r][c];
        if(teleport >= 'a' && teleport <= 'z' && !flag[teleport-'a']) {
            flag[teleport-'a'] = true;
            foreach(tele_coor, mapping[teleport]) {
                auto [rrr, ccc] = tele_coor;
                if(visited[rrr][ccc]) continue;
                visited[rrr][ccc] = true;
                if(chmin(dist[rrr][ccc], d+1)) q.emplace(rrr, ccc);
            }
        }
    }


    cout << ans << endl;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    solve();
    return 0;
}

    
    
#include <algorithm>
#include <bitset>
#include <climits>
#include <cmath>
#include <iostream>
#include <vector>
#include <map>
#include <memory>
#include <list>
#include <deque>
#include <queue>
#include <iomanip>
#include <set>
#include <stack>
#include <numeric>
#include <unordered_set>
#include <unordered_map>
#include <string.h>
#include <functional>
#include <sstream>

using namespace std;

#define REP(i,n) for (decltype(n) i = 0; i < n; i++)
#define THE_MOD 1'000'000'007

using ll = long long;
using ivec = vector<int>;
using lvec = vector<long>;
using ipair = pair<int, int>;
using llvec = vector<ll>;
using llpair = pair<ll, ll>;

#define umap unordered_map
#define uset unordered_set

template<typename T> ostream& operator <<(ostream& os, const vector<T> &v) { auto n = v.size(); REP(i,n) os << (i ? " " : "") << v[i]; return os; }
template<typename T> istream& operator >>(istream& is, vector<T> &v) { for(auto &e : v) is >> e; return is; }
template<typename T, typename U> ostream& operator <<(ostream& os, const pair<T, U> &p) { os << p.first << " " << p.second; return os; }
template<typename T, typename U> istream& operator >>(istream& is, pair<T, U> &p) { is >> p.first >> p.second; return is; }

void in() {} template <typename T, typename... Args> void in(T& t, Args& ...args) { cin >> t; in(args...); }
void out() { cout << endl; } template <typename T, typename... Args> void out(const T& t, const Args& ...args) { cout << t; if (sizeof...(args)) cout << " "; out(args...); }

constexpr ll LLINF = numeric_limits<ll>::max();

template<class T> void sort(T& v) {	sort(v.begin(), v.end()); }
template<class T> void rsort(T& v) { sort(v.begin(), v.end(), greater<typename T::value_type>()); }

void YN(bool b) {	cout << (b ? "Yes" : "No") << endl; }

template <typename T = ll, typename U = ll>
vector<T> Dijkstra(const vector<vector<pair<U,T>>>& edges, U start, U numNodes)
{
	using Node = pair<U,T>;
	auto compare = [](Node a, Node b){ return a.second > b.second;};
	priority_queue<Node, vector<Node>, decltype(compare)> q{compare};

	vector<T> costs(numNodes, numeric_limits<T>::max());

	q.emplace(start, 0);
	while (!q.empty()) {
		auto [from, cost] = q.top();
		q.pop();
		if (cost > costs[from]) continue;

		for (const auto& edge : edges[from]) {
			auto to = edge.first;
			auto newCost = cost + edge.second;
			if (newCost < costs[to]) {
				costs[to] = newCost;
				q.emplace(to, newCost);
			}
		}
	}
	return costs;
}

struct Range {
	ll x;
	ll y;
	Range(ll x, ll y) : x(x), y(y)
	{
		if (y > x) swap(x,y);
	}

	struct Iterator {
		using difference_type   = ptrdiff_t;
		using value_type        = ll;
		using pointer           = ll*;
		using reference         = ll&;
		using iterator_category = std::random_access_iterator_tag;
		Iterator() = default;
		Iterator(ll n) : n(n) {}
		ll n;
		bool operator!=(const Iterator&rhs) const { return n != rhs.n; }
		bool operator==(const Iterator&rhs) const { return n == rhs.n; }
		Iterator& operator++() { n++; return *this; }
		Iterator& operator--() { n--; return *this; }
		Iterator& operator+=(ll x) { n+=x; return *this; }
		ll operator*() const { return n; }
		ptrdiff_t operator-(const Iterator&rhs) const { return n - rhs.n; }
	};

	Iterator begin() { return Iterator(x); }
	Iterator end() { return Iterator(y); }
};

ll run()
{
	ll n;
	in(n);
	ll r = -1;
	REP(i, n) {
		ll a, p, x;
		in(a,p,x);
		if (a < x) {
			if (r == -1) {
				r = p;
			} else {
				r = min(r, p);
			}
		}

	}
	out(r);
	return 0;
}

int main()
{
	cout << fixed << setprecision(15);
	auto r = run();
	//YN(r);
	//out(r);
	//cout << r << endl;
	return 0;
}
