#include <bits/stdc++.h>
#define rep(i,n) for(int i=0,del##i##verme=int(n);i<del##i##verme;++i)
#define rep1(i,n) for(int i=1,parano##i##a=int(n);i<=parano##i##a;++i)
#define per(i,n) for(int i=int(n)-1;i>=0;--i)
#define per1(i,n) for(int i=int(n);i>=1;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define y0 LingLuo
#define y1 VividCycle
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using namespace std;
const ll mod1=998244353;
const ll mod2=1000000007;
unsigned time_related_rand()
{
return unsigned(std::chrono::steady_clock::now().time_since_epoch().count());
}
#define P 1
#define Q 2
#define LEAF 0
namespace PQTree{
int n;
vector<int> g[1000005];int cnt=0;
int stk[1000005],ct;
int type[1000005];
int color[1000005];
int root;
int NewNode()
{
if(ct) return stk[ct--];
return ++cnt;
}
void fail()
{
cout<<"NO\n";
exit(0);
}
void print_tree(int x)
{
if(type[x]==LEAF)
{
cout<<char(96+x);
}
else if(type[x]==P)
{
cout<<"P{";
for(int y:g[x])
{
print_tree(y);
}
cout<<"}";
}
else
{
cout<<"Q{";
for(int y:g[x])
{
print_tree(y);
}
cout<<"}";
}
}
void print_tree()
{
print_tree(root);cout<<'\n';
}
int NewNode(const vector<int>&vc,int tp)
{
if(int(vc.size())==1) return vc[0];
int tmp=NewNode();
type[tmp]=tp;
g[tmp]=vc;
return tmp;
}
void Delete(int x)
{
g[x].clear();
stk[++ct]=x;
}
void init(int N)
{
n=N;
rep1(i,cnt) g[i].clear();
ct=0;cnt=n;
root=NewNode();g[root].reserve(n);
rep1(i,n) g[root].pb(i);
rep1(i,n) type[i]=LEAF;
type[root]=P;
}
void find_color(int x)
{
if(type[x]==LEAF) return ;
color[x]=0;
for(int y:g[x])
{
find_color(y);
color[x]|=color[y];
}
// cout<<"color [ "<<x<<" ] = "<<color[x]<<endl;
}
vector<int> temp;
vector<int> white,black,gray;
bool is_sorted(int x)// x is Q
{
int lst=0;
for(int y:g[x])
{
int cur=1^color[y];
if(cur<lst) return false;
lst=cur;
}
return true;
}
void split(int x)// add split(x) after temp
{
if(color[x]==1||color[x]==2)
{
temp.pb(x);return ;
}
if(type[x]==P)
{
white.clear();
black.clear();
int cntg=0,target=0;
for(int y:g[x])
{
if(color[y]==1) white.pb(y);
else if(color[y]==2) black.pb(y);
else
{
++cntg;target=y;
}
}
if(cntg>=2)
{
fail();
}
int qwq=0;if(!black.empty()) qwq=NewNode(black,P);
if(!white.empty()) temp.pb(NewNode(white,P));
if(cntg) split(target);
if(qwq) temp.pb(qwq);
Delete(x);
return ;
}
if(!is_sorted(x))
{
reverse(g[x].begin(),g[x].end());
if(!is_sorted(x))
{
fail();
}
}
int cntg=0;
for(int y:g[x]) if(color[y]==3) ++cntg;
if(cntg>=2) fail();
for(int y:g[x])
{
if(color[y]==3) split(y);
else temp.pb(y);
}
Delete(x);
}
void reduce(int x)
{
while(int(g[x].size())==1&&g[x][0]>n)
{
int cur=g[x][0];
g[x].swap(g[cur]);
type[x]=type[cur];
Delete(cur);
}
for(int y:g[x])
{
reduce(y);
}
}
int solve(int x)
{
// cout<<"? solve "<<x<<" color = "<<color[x]<<" type = "<<"LPQ"[type[x]]<<endl;
if(color[x]==1||color[x]==2) return x;
if(type[x]==P)
{
white.clear();
black.clear();
gray.clear();
for(int y:g[x])
{
if(color[y]==1) white.pb(y);
else if(color[y]==2) black.pb(y);
else if(color[y]==3) gray.pb(y);
}
// cout<<"?! "<<gray.size()<<" gray nodes"<<endl;
if(int(gray.size())>2)
{
fail();
}
int cur=0;if(!black.empty()) cur=NewNode(black,P);
int res=NewNode();type[res]=P;g[res].swap(white);
white.clear();black.clear();
if(int(gray.size())==0)
{
if(cur) g[res].pb(cur);
Delete(x);
return res;
}
if(int(gray.size())==1&&cur==0)
{
g[res].pb(solve(gray[0]));
Delete(x);
return res;
}
int res2=NewNode();
g[res].pb(res2);
type[res2]=Q;
if(int(gray.size())==1)
{
temp.clear();
// print_tree(gray[0]);
split(gray[0]);
// cout<<"split -> ";
// for(int y:temp)
// {
// print_tree(y);cout<<" ";
// }
// cout<<endl;
g[res2].swap(temp);
if(cur) g[res2].pb(cur);
Delete(x);
return res;
}
temp.clear();split(gray[0]);g[res2].swap(temp);
temp.clear();if(cur)g[res2].pb(cur);split(gray[1]);reverse(temp.begin(),temp.end());
for(int y:temp) g[res2].pb(y);
Delete(x);
return res;
}
int l=0,r=int(g[x].size())-1;
while(color[g[x][l]]==1) ++l;
while(color[g[x][r]]==1) --r;
for(int i=l+1;i<=r-1;++i) if(color[g[x][i]]!=2)
{
fail();
}
int res=NewNode();type[res]=Q;
if(l==r&&color[g[x][l]]==3)
{
int res2=solve(g[x][l]);
g[res].swap(g[x]);g[res][l]=res2;
Delete(x);
return res;
}
for(int y:g[x])
{
if(color[y]!=3)
{
g[res].pb(y);
}
else
{
temp.clear();
split(y);
if(y==g[x][r]) reverse(temp.begin(),temp.end());
for(int z:temp) g[res].pb(z);
}
}
Delete(x);
return res;
}
void add_constraint(int cl[])// 0 and 1
{
rep1(i,n) color[i]=cl[i]+1;
find_color(root);
root=solve(root);
// print_tree();
reduce(root);
}
ll fac[100005];
ll calc_result(int x)
{
if(type[x]==LEAF) return 1;
ll xx=1;
for(int y:g[x]) xx=xx*calc_result(y)%mod1;
if(type[x]==Q)
{
if(int(g[x].size())>1) xx=xx*2%mod1;
}
else
{
xx=xx*fac[g[x].size()]%mod1;
}
return xx;
}
ll calc_result()
{
fac[0]=1;
rep1(i,n) fac[i]=fac[i-1]*i%mod1;
return calc_result(root);
}
vector<int> perm;
void find_perm(int x)
{
if(type[x]==LEAF)
{
perm.pb(x);return ;
}
for(int y:g[x]) find_perm(y);
}
vector<int> find_perm()
{
perm.clear();
find_perm(root);
return perm;
}
};
int t,n,m;string s[1005],ts;
int c[100005];
vector<int> answer;
void query()
{
cin>>n;
PQTree::init(n);
rep1(i,n)
{
cin>>s[i];
rep1(j,n) c[j]=int((s[i][j-1])&1);
// cout<<"? add"<<endl;
// PQTree::print_tree();
PQTree::add_constraint(c);
// cout<<"added"<<endl;
}
// PQTree::print_tree();
answer=PQTree::find_perm();
// cout<<answer[0]<<'\n';
cout<<"YES\n";
rep1(i,n)
{
ts="";
for(int x:answer) ts+=s[i][x-1];
cout<<ts<<'\n';
}
}
int main()
{
ios_base::sync_with_stdio(false);cin.tie(0);
t=1;
while(t--)query();
return 0;
}
/* things to check
1. int overflow or long long memory need
2. recursion/array/binary search/dp/loop bounds
3. precision
4. special cases(n=1,bounds)
5. delete debug statements
6. initialize(especially multi-tests)
7. = or == , n or m ,++ or -- , i or j , > or >= , < or <=
8. keep it simple and stupid
9. do not delete, use // instead
10. operator priority
11. is there anything extra to output?
12. ...
*/
/* something to think about
1. greedy? dp? searching? dp with matrix/ segment tree? binary search?
2. If contains "not", why not ?????? or few affect?
*/