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

constexpr int INF = 1e9;

vector<int> operator+(vector<int> l, vector<int> const& r) {
    for(int i = 0; i < (int)l.size(); ++i) {
        l[i] += r[i];
    }
    return l;
}
vector<int> operator-(vector<int> v) {
    for(int i = 0; i < (int)v.size(); ++i) {
        v[i] = -v[i];
    }
    return v;
}
vector<int> operator-(vector<int> l, vector<int> const& r) {
    for(int i = 0; i < (int)l.size(); ++i) {
        l[i] -= r[i];
    }
    return l;
}
vector<int> operator*(vector<int> v, int x) {
    for(int i = 0; i < (int)v.size(); ++i) {
        v[i] *= x;
    }
    return v;
}


using weight = vector<int>;

struct edge {
    int to, cap;
    weight cost;
    int rev;
};

using edges = std::vector<edge>;
using graph = std::vector<edges>;

void add_edge(graph& g, int from, int to, int cap, weight cost) {
    g[from].push_back(edge{to, cap, cost, (int)g[to].size()});
    g[to].push_back(edge{from, 0, -cost, (int)g[from].size()-1});
}

weight min_cost_flow(graph& g, int s, int t, int f) {
    using P = pair<vector<int>, int>;

    weight res(52);
    std::vector<weight> h(g.size(), vector<int>(52));
    std::vector<weight> dist(g.size());
    std::vector<int> prevv(g.size()), preve(g.size());
    while(f > 0) {
        std::priority_queue<P, std::vector<P>, std::greater<P>> que;
        std::fill(dist.begin(), dist.end(), vector<int>(52, INF));
        dist[s] = vector<int>(52, 0);
        que.push(P{dist[s], s});
        while(!que.empty()) {
            P p = que.top(); que.pop();
            int v = p.second;
            if(dist[v] < p.first) {
                continue;
            }
            for(int i = 0; i < (int)g[v].size(); ++i) {
                edge& e = g[v][i];
                if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
                    dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    que.push(P{dist[e.to], e.to});
                }
            }
        }
        if(dist[t][0] == INF) {
            return vector<int>(52, -1);
        }
        for(int v=0; v<g.size(); ++v) {
            h[v] = h[v] + dist[v];
        }

        int d = f;
        for(int v = t; v != s; v = prevv[v]) {
            d = min(d, g[prevv[v]][preve[v]].cap);
        }
        f -= d;
        res = res + h[t] * d;
        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;
}


int main() {
    string const alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    int N;
    cin >> N;
    vector<string> s(N);
    for(int i = 0; i < N; ++i) {
        cin >> s[i];
    }

    graph g(N + N + 2);
    int const source = N + N, sink = N + N + 1;
    for(int i = 0; i < N; ++i) {
        add_edge(g, source, i, 1, vector<int>(52, 0));
        add_edge(g, i + N, sink, 1, vector<int>(52, 0));
    }
    for(int i = 0; i < N; ++i) {
        for(int j = 0; j < N; ++j) {
            vector<int> vec(52);
            vec[alphabets.find(s[i][j])] = -1;
            add_edge(g, i, j + N, 1, vec);
        }
    }

    auto res = min_cost_flow(g, source, sink, N);
    for(int i = 0; i < 52; ++i) {
        cout << string(-res[i], alphabets[i]);
    }
    cout << endl;
}


Measured memory_bytes: 4536