#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAX = 52;
const int MAX_V = 100010;
typedef int Capacity;
typedef vector<int> Cost;
const Cost inf = Cost(MAX, 1000000);
const Cost zero = Cost(MAX, 0);

Cost operator -(Cost c) {
	for(auto& a : c) a *= -1;
	return c;
}

Cost operator +(Cost c1, Cost c2) {
	for(int i = 0; i < c1.size(); i++) c1[i] += c2[i];
	return c1;
}

Cost operator -(Cost c1, Cost c2) {
	for(int i = 0; i < c1.size(); i++) c1[i] -= c2[i];
	return c1;
}

bool operator ==(Cost c1, Cost c2) {
	for(int i = 0; i < c1.size(); i++) {
		if(c1[i] != c2[i]) return false;
	}
	return true;
}

struct Edge {
	int dst;
	Capacity cap, cap_orig;
	Cost cost;
	int revEdge; bool isRev;
	Edge(int dst, Capacity cap, Cost cost, int revEdge, bool isRev)
		:dst(dst), cap(cap), cap_orig(cap), cost(cost), revEdge(revEdge), isRev(isRev) {
	}
};


struct PrimalDual {
	int n;
	vector<vector<Edge> > g;
	vector<int> top;
	PrimalDual(int n_) : n(n_), g(vector<vector<Edge> >(n_)) {}
	void add_edge(int src, int dst, Capacity cap, Cost cost) { // ?????????
		g[src].push_back(Edge{ dst, cap, cost, (int)g[dst].size(), false });
		g[dst].push_back(Edge{ src, 0, -cost, (int)g[src].size() - 1, true });
	}
	Cost solve(int s, int t, int f) {
		Cost res(52, 0);
		static Cost h[MAX_V], dist[MAX_V];
		static int prevv[MAX_V], preve[MAX_V];

		fill(h, h + n, zero);
		if(top.size()) {
			assert(top.size() == n);
			for(int i = 0; i < n; i++) {
				int v = top[i];
				for(int i = 0; i < g[v].size(); i++) {
					Edge& e = g[v][i];
					if(e.cap == 0) continue;
					int u = e.dst;
					h[u] = min(h[u], h[v] + e.cost);
				}
			}
		}

		while(f > 0) {
			typedef pair<Cost, int> pcv;
			priority_queue<pcv, vector<pcv>, greater<pcv> > q;
			for(int i = 0; i < n; i++) {
				dist[i] = inf;
			}
			dist[s] = Cost(MAX, 0);
			q.push(pcv(Cost(MAX, 0), s));
			while(q.size()) {
				pcv p = q.top(); q.pop();
				int v = p.second;
				if(dist[v] < p.first) continue;
				for(int i = 0; i < g[v].size(); i++) {
					Edge &e = g[v][i];
					if(e.cap > 0 && dist[e.dst] > dist[v] + e.cost + h[v] - h[e.dst]) {
						dist[e.dst] = dist[v] + e.cost + h[v] - h[e.dst];
						prevv[e.dst] = v;
						preve[e.dst] = i;
						q.push(pcv(dist[e.dst], e.dst));
					}
				}
			}
			if(dist[t] == inf) {
				return inf;// !!!!!
			}
			for(int v = 0; v < n; v++) {
				h[v] = h[v] + dist[v];
			}
			// s-t ????????????????????£??????????????????
			int d = f;
			for(int v = t; v != s; v = prevv[v]) {
				d = min(d, g[prevv[v]][preve[v]].cap);
			}
			f -= d;
			for(int i = 0; i < MAX; i++) {
				res[i] += d * h[t][i];
			}
			for(int v = t; v != s; v = prevv[v]) {
				Edge &e = g[prevv[v]][preve[v]];
				e.cap -= d;
				g[v][e.revEdge].cap += d;
			}
		}
		return res;
	}
	// ??????????????????=???????????????-?????¨??????????????¨???
	/*void view() {
		for(int i = 0; i < g.size(); i++) {
		for(int j = 0; j < g[i].size(); j++) {
		if(!g[i][j].isRev) {
		Edge& e = g[i][j];
		printf("%3d->%3d (flow:%d)\n", i, e.dst, e.cap_orig - e.cap);
		}
		}
		}
		}*/
};

string b[50];

int conv(char c) {
	if('A' <= c && c <= 'Z') return c - 'A';
	return c - 'a' + 26;
}

char deconv(int id) {
	if(id <= 25) return 'A' + id;
	return 'a' + (id - 26);
}

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

	int N;
	cin >> N;
	for(int i = 0; i < N; i++) {
		cin >> b[i];
	}

	PrimalDual pd(2 * N + 2);
	int S = 2 * N, T = S + 1;
	for(int i = 0; i < N; i++) {
		for(int j = 0; j < N; j++) {
			int c = conv(b[i][j]);
			Cost cost(MAX, 0);
			cost[c] = -1;
			pd.add_edge(i, N + j, 1, cost);
		}
		pd.add_edge(S, i, 1, zero);
		pd.add_edge(i + N, T, 1, zero);
	}

	Cost res = pd.solve(S, T, N);
	assert(res != inf);
	for(int i = 0; i < MAX; i++) {
		for(int j = 0; j < -res[i]; j++) {
			cout << deconv(i);
		}
	}
	cout << endl;
}

Measured memory_bytes: 9316