#include "bits/stdc++.h"
using namespace std;

typedef long long ll;
#define REP(i, n) for(int i = 0;i < n;i++)
#define REPR(i, n) for(int i = n;i >= 0;i--)
#define FOR(i, m, n) for(int i = m;i < n;i++)

int dy[] = { 0, 0, 1, -1 };
int dx[] = { 1, -1, 0, 0 };

ll A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z;

namespace aojCheese {
	void aojCheese();
}
int main()
{
	aojCheese::aojCheese();
	return 0;
}

//* ?????????n??????????????\??????????????????????????????????????????
template <typename T>
vector<T> INP(ll n)
{
	vector<T> x;
	REP(i, n) {
		T tmp; cin >> tmp;
		x.push_back(tmp);
	}
	return x;
}
//* n??????1????????????????????\?????????????????????????????¨??????????????????
vector<char> SPRIT_STRING(ll n)
{
	string str; cin >> str;
	vector<char> cs(n);
	REP(i, n) cs[i] = str[i];
	return cs;
}
//* ??§?¨?nx, ny???Width,Height?????????????????????????????????????????§??????
inline bool rangeCheck2D(int nx, int ny, int Width, int Height)
{
	return nx >= 0 and nx < Width and ny >= 0 and ny < Height;
}

// 0558
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0558
namespace aojCheese {
	vector<ll> minStep(9);

	bool minimize(
		int target,
		const vector<string>& field,
		vector<ll>& minDist,
		int x, int y
	)
	{
		minDist[y * W + x] = 0;
		queue< pair<int, int> > update;
		update.push(make_pair(x, y));

		while (not(update.empty())) {
			int ux = update.front().first;
			int uy = update.front().second;
			update.pop();

			if (field[uy][ux] - '0' == target) {
				minStep[target - 1] = minDist[uy * W + ux];
				return true;
			}

			int ccost = minDist[uy * W + ux];
			REP(i, 4) {
				int nx = ux + dx[i];
				int ny = uy + dy[i];
				if (rangeCheck2D(nx, ny, W, H) and field[ny][nx] != 'X' and minDist[W*ny + nx] == INT64_MAX) {
					update.push(make_pair(nx, ny));
					minDist[W*ny + nx] = ccost + 1;
				}
			}
		}
		/*
		if (target == 7) {
			REP(i, 10) {
				REP(j, 10) {
					ll value = minDist[i*W + j];
					if (value > 100)
						cout << setw(5) << 0;
					else
						cout << setw(5) << minDist[i*W + j];
				}
				cout << endl;
			}
			cout << endl;
		}*/

		return false;
	}

	void aojCheese()
	{
		cin >> H >> W >> N;
		REP(i, N) minStep[i] = INT64_MAX;
		vector<int> sX(N+1), sY(N+1);
		vector<string> field(H);
		REP(i, H) {
			cin >> field[i];
			REP(j, W) {
				char f = field[i][j];
				if (f == 'S') {
					sX[0] = j; sY[0] = i;
				}
				else if ('1' <= f and f <= ('0' + N)) {
					sX[f - '0'] = j; sY[f - '0'] = i;
				}
			}
		}
		REP(i, N) {
			vector<ll> minDist(H*W, INT64_MAX);
			minimize(i + 1, field, minDist, sX[i], sY[i]);
		}
		cout << accumulate(minStep.begin(), minStep.begin() + N, 0) << endl;
	}
}

// 0121
// 0525
// 

// unsolved
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1133&lang=jp
namespace aojWaterTank {
	void aojWaterTank()
	{
		cin >> D;
		REP(d, D) {
			cin >> N; // ?????????????????°
			vector< pair<int, int> > plates(N); // first X??§?¨?, second ??????
			REP(i, N) cin >> plates[i].first >> plates[i].second;
			cin >> M; // ?????£?????°
			vector< pair<int, int> > faucets(M); // first X??§?¨?, second ??????
			REP(i, M) cin >> faucets[i].first >> faucets[i].second;
			cin >> L; // ?°´??????????????¬????????°
			vector<int> mX(L), time(L); // first X??§?¨?, second ??????
			REP(i, L) cin >> mX[i] >> time[i];

			

				int EX_TIME = *max_element(time.begin(), time.end());
			vector<double> height(N + 1);
			REP(t, EX_TIME) {
				REP(m, M) {
					int fx = faucets[m].first;
					double fw = (double)faucets[m].second;
					int fIndex = 0; // ?????£????????????????????????height???Index
					while ((fIndex <= N - 1) and plates[fIndex].first < fx)
						fIndex++;
					double currentHeight = height[fIndex]; // ?????£???????????????

					pair<int, int> leftWall, rightWall; // ??????????£????X??§?¨??????????
					bool leftDone = false, rightDone = false;
					if (fIndex == 0) {
						leftWall = make_pair(0, 50);
						leftDone = true;
					}
					else if (fIndex == N) {
						rightWall = make_pair(100, 50);
						rightDone = true;
					}
					if (not(leftDone)) {
						leftWall = plates[fIndex - 1];
						int wallIndex = fIndex;
						while ((wallIndex > 0) and leftWall.second < currentHeight) {
							wallIndex--;
							leftWall = plates[wallIndex];
						}
					}
					if (not(rightDone)) {
						rightWall = plates[fIndex];
						int wallIndex = fIndex;
						while ((wallIndex < N - 1) and rightWall.second < currentHeight) {
							wallIndex++;
							rightWall = plates[wallIndex];
						}
					}

					double plus = fw / (30.0 * (rightWall.first - leftWall.first));
					double newHeight = height[fIndex] + plus;
					if (newHeight > rightWall.second and newHeight > rightWall.second) {

					}
				}
				cout << EX_TIME << endl;
			}
		}
	}
}

// solved
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2298
// ?????¢??§???????????¢??£????????±??????
namespace aojStartingLine {
	void aojStartingLine()
	{
		cin >> N >> K >> T >> U >> V >> L;
		vector<int> ds = INP<int>(N);

		double time = 0.0;
		int restBoostL = 0;
		int restCarrot = 0;
		int currentIndex = -1;
		REP(i, L) {
			if (restBoostL > 0) {
				time += 1.0 / (double)V;
				restBoostL--;
			}
			else
				time += 1.0 / (double)U;

			if (currentIndex == -1 and ds[0] == i + 1) {
				currentIndex = 0;
				restBoostL = T * V;
			}
			else if (currentIndex >= 0 and currentIndex < (N - 1) and ds[currentIndex + 1] == (i + 1)) {
				if (restBoostL == 0) {
					restBoostL = T*V;
				}
				else if (restCarrot < K) {
					restCarrot++;
				}
				else {
					restBoostL = T*V;
				}
				currentIndex++;
			}

			if (restBoostL == 0 and restCarrot > 0) {
				restBoostL = T * V;
				restCarrot--;
			}
		}

		cout << fixed << setprecision(10) << time << endl;
	}
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0118
namespace aojPropertyDistribution {
	void journey(
		vector<bool>& visited,
		vector<string>& field,
		int x, int y)
	{
		if (visited[W*y + x])
			return;
		else {
			char f = field[y][x];
			visited[W*y + x] = true;
			REP(i, 4) {
				int nx = x + dx[i];
				int ny = y + dy[i];
				if (rangeCheck2D(nx, ny, W, H) and f == field[ny][nx])
					journey(visited, field, nx, ny);
			}
		}
	}

	void aojPropertyDistribution()
	{
		while (true) {
			cin >> H >> W;
			if (H == 0 and W == 0) break;
			vector<bool> visited(H*W);
			vector<string> field(H);
			REP(i, H) cin >> field[i];

			int cnt = 0;
			REP(i, H) {
				REP(j, W) {
					if (visited[W*i + j])
						continue;
					cnt++;
					journey(visited, field, j, i);
				}
			}
			cout << cnt << endl;
		}
	}
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0033
namespace aojBall {
	bool dfs(
		int pos, vector<int>& data,
		int left, int right)
	{
		int d = data[pos];
		if (d < left and d < right)
			return false;
		else if (pos == 9)
			return true;
		bool rLeft = (d > left) ? dfs(pos + 1, data, d, right) : false;
		bool rRight = (d > right) ? dfs(pos + 1, data, left, d) : false;
		return rLeft or rRight;
	}
	void aojBall()
	{
		cin >> N;
		REP(i, N) {
			vector<int> data = INP<int>(10);
			if (dfs(0, data, 0, 0))
				cout << "YES" << endl;
			else
				cout << "NO" << endl;
		}
	}
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2424
namespace aojKakezan {
	void aojKakezan() {
		cin >> Q;
		REP(i, Q) {
			string current; cin >> current;
			ll cnt = 0;
			while (current.size() > 1) {
				ll maxNext = 0;
				REP(p, current.size() - 1) {
					ll a = stoi(current.substr(0, p + 1));
					ll b = stoi(current.substr(1 + p, current.size() - (p + 1)));
					maxNext = max(maxNext, a * b);
				}
				current = to_string(maxNext);
				cnt++;
			}
			cout << cnt << endl;
		}
	}
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2102&lang=jp
namespace aojRummy {
	struct Card {
		ll number;
		char color;
	} Card_t;

	bool comp(const Card& a, const Card& b)
	{
		return a.number < b.number;
	}

	bool rummyCheck(vector<Card> cards)
	{
		if (cards.size() == 0) return true;
		if (cards.size() % 3 != 0) return false;
		sort(cards.begin(), cards.end(), comp);
		bool okay = false;
		do {
			int repNum = cards.size() / 3;
			bool localOkay = true;
			REP(i, repNum) {
				ll zero = cards[i * 3].number;
				ll one = cards[i * 3 + 1].number;
				ll two = cards[i * 3 + 2].number;
				if (not((zero == one and one == two) or ((zero + 1) == one and (one + 1) == two)))
					localOkay = false;
			}
			if (localOkay)
				okay = true;
		} while (next_permutation(cards.begin(), cards.end(), comp));
		return okay;
	}

	void aojRummy()
	{
		cin >> T;

		N = 9;
		REP(t, T) {
			vector<Card> cards(N);
			REP(i, 9) cin >> cards[i].number;
			REP(i, 9) cin >> cards[i].color;

			vector<Card> red, green, blue;
			REP(i, N) {
				Card c = cards[i];
				if (c.color == 'R') red.push_back(c);
				else if (c.color == 'G') green.push_back(c);
				else blue.push_back(c);
			}

			if (rummyCheck(red) and rummyCheck(blue) and rummyCheck(green))
				cout << 1 << endl;
			else
				cout << 0 << endl;
		}
	}
}

//* http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1129
void aojHanafudaShuffle()
{
	N = R = 1;
	while (true) {
		cin >> N >> R;
		if (N == 0 and R == 0) break;

		vector<ll> cards(N);
		REP(i, N) cards[i] = i + 1;

		REP(i, R) {
			cin >> P >> C;
			rotate(cards.begin() + (N - (C + P - 1)), cards.begin() + (N - (P - 1)), cards.end());
			//vector<ll> tmp(C);
			//copy(cards.begin() + (N - (C + P - 1)), cards.begin() + N - (P - 1), tmp.begin());
			//copy(cards.begin() + (N - (P - 1)), cards.end(), cards.begin() + (N - (C + P - 1)));
			//copy(tmp.begin(), tmp.end(), cards.begin() + (N - C));
		}

		cout << cards[cards.size() - 1] << endl;
	}
}


Measured memory_bytes: 12068