#include <bits/stdc++.h>
using namespace std;
#define FOR(i,k,n) for(int i = (int)(k); i < (int)(n); i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(a) a.begin(), a.end()
#define MS(m,v) memset(m,v,sizeof(m))
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;
const int MOD = 1000000007;
const ld EPS = 1e-12;
template<class T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template<class T> T &chmax(T &a, const T &b) { return a = max(a, b); }

/*--------------------template--------------------*/
int n;
typedef vi Weight;
typedef int Flow;
Weight ZERO;
Weight INF;

Weight operator-(const Weight& v)
{
	Weight res = v;
	REP(i, res.size()) res[i] *= -1;
	return res;
}

Weight operator+(const Weight& a, const Weight b)
{
	Weight res = a;
	REP(i, res.size()) res[i] += b[i];
	return res;
}

struct Edge {
	int src, dest, rev;
	Flow cap;
	Weight cost;
	bool operator < (const Edge &rhs) const
	{
		return cost > rhs.cost;
	}
	Edge(int s, int d) : src(s), dest(d) { ; }
	Edge(int s, int d, int c) : src(s), dest(d), cost(c) { ; }
	Edge(int s, int d, int r, Flow cp, Weight cst) : src(s), dest(d), rev(r), cap(cp), cost(cst) { ; }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void add_edge(Graph &g, int from, int to, Flow cap, Weight cost)
{
	g[from].push_back(Edge(from, to, (int)g[to].size(), cap, cost));
	g[to].push_back(Edge(to, from, (int)g[from].size() - 1, 0, -cost));
}

Weight mincost_flow(Graph &g, int s, int t, Flow f)
{
	const int n = g.size();
	vi emp(52);
	Weight res = emp;
	Array dist(n);
	vi prevv(n), preve(n);
	while (f > 0)
	{
		REP(i, n) dist[i] = (i == s) ? ZERO : INF;
		bool update = true;
		while (update)
		{
			update = false;
			for (int v = 0; v < n; v++)
			{
				if (dist[v] == INF) continue;
				REP(i, g[v].size())
				{
					Edge& e = g[v][i];
					if (e.cap > 0 && dist[e.dest] > dist[v] + e.cost)
					{
						dist[e.dest] = dist[v] + e.cost;
						prevv[e.dest] = v;
						preve[e.dest] = i;
						update = true;
					}
				}
			}
		}
		Flow d = f;
		for (int v = t; v != s; v = prevv[v])
		{
			d = min(d, g[prevv[v]][preve[v]].cap);
		}
		f -= d;
		assert(d == 1);
		//res += d * dist[t];
		res = res + dist[t];
		for (int v = t; v != s; v = prevv[v])
		{
			Edge &e = g[prevv[v]][preve[v]];
			e.cap -= d;
			g[v][e.rev].cap += d;
		}
	}
	return res;
}

map<char, vi> mp;

int main()
{
	cin.sync_with_stdio(false); cout << fixed << setprecision(10);
	ZERO.resize(52);
	INF.resize(52, 1000000);
	int n; cin >> n;
	vs fld(n);
	REP(i, n) cin >> fld[i];
	Graph g(n * 2 + 2);
	int src = n * 2, sink = n * 2 + 1;
	REP(i, 26)
	{
		vi v(52);
		v[i] = -1;
		mp['A' + i] = v;
	}
	REP(i, 26)
	{
		vi v(52);
		v[i+26] = -1;
		mp['a' + i] = v;
	}
	vi emp(52);
	REP(i, n)
	{
		add_edge(g, src, i, 1, emp);
		add_edge(g, n + i, sink, 1, emp);
	}
	REP(i, n)REP(j, n)
	{
		add_edge(g, i, n + j, 1, mp[fld[i][j]]);
	}
	vi res = mincost_flow(g, src, sink, n);
	string ans;
	REP(i, 26)
	{
		REP(j, -res[i]) ans += char('A' + i);
	}
	REP(i, 26)
	{
		REP(j, -res[i+26]) ans += char('a' + i);
	}
	cout << ans << endl;
	return 0;
}

Measured memory_bytes: 4512