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

typedef long long LL;

const int N = 15;

int n, m;
string s[15], t[15], Map[15];
bool vis[15];

vector <int> S[15];
int kS;

int loc[15];

/*void Print(){
    for (int i = 0; i < n; i++) cout << Map[i] << endl;
    system("pause");
}

void PrintLine(){
    for (int i = 1; i <= kT; i++){
        for (int j = 0; j < T[i].size(); j++)
            cout << T[i][j] << ' ';
        cout << endl;
    }
}*/

bool CheckAll(){
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++){
            int x = n - i - 1;
            int y = m - j  - 1;
            if (Map[i][loc[j]] != Map[x][loc[y]]) return false;
        }
    return true;
}

void DecideCol(int now){
    if (now == m - 1){
        if (CheckAll()) { printf("YES\n"); exit(0); }
        return ;
    }

    if (loc[now] != now) DecideCol(now + 1);
    else {
        for (int i = now + 1; i < m; i++) if (loc[i] == i){
            swap(loc[i], loc[now]);
            DecideCol(now + 1);
            swap(loc[i], loc[now]);
        }
        DecideCol(now + 1);
    }
}

void CheckCol(){
    for (int i = 0; i < m; i++) loc[i] = i;
    DecideCol(0);
}

void DecideRow(int now, int up, int down, int cnt){  // now 第几个集合，up上行，down下行，cnt这个集合已经用了多少个
    //printf("now=%d, up=%d, down=%d, cnt=%d\n", now, up, down, cnt);
    //system("pause");
    if (now > kS) { CheckCol(); /*Print();*/ return ; }
    if (up == down){                  // 单独处理奇集合
        for (int i = 0; i < S[now].size(); i++) if (!vis[S[now][i]]){
            Map[up] = s[S[now][i]];
            break;
        }
        DecideRow(now + 1, up + 1, down - 1, 0);
        return ;
    }
    //cout << "::" << endl;
    for (int i = 0; i < S[now].size() - 1; i++) if (!vis[S[now][i]]){
        //cout << S[now][i] << ':';
        vis[S[now][i]] = true;
        Map[up] = s[S[now][i]];
        for (int j = i + 1; j < S[now].size(); j++) if (!vis[S[now][j]]){
            //cout << S[now][j] << ' ';
            vis[S[now][j]] = true;
            Map[down] = s[S[now][j]];
            if (cnt + 2 == S[now].size()) DecideRow(now + 1, up + 1, down - 1, 0);
            else DecideRow(now, up + 1, down - 1, cnt + 2);
            vis[S[now][j]] = false;
        }
        //cout << endl;
        vis[S[now][i]] = false;
    }
}

int main(){
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++){
        cin >> s[i]; t[i] = s[i];
        sort(t[i].begin(), t[i].end());
    }

    S[++kS].push_back(0);
    for (int i = 1; i < n; i++){
        bool flag = false;
        for (int j = 1; j <= kS; j++)
            if (t[i] == t[S[j][0]]){
                S[j].push_back(i);
                flag = true; break;
            }
        if (!flag) S[++kS].push_back(i);
    }

    /*for (int i = 1; i <= kS; i++){
        for (int j = 0; j < S[i].size(); j++)
            cout << S[i][j] << ' ';
        cout << endl;
    }*/
    int cnt = 0;
    for (int i = 1; i <= kS; i++)
        if (S[i].size() & 1) cnt++;
    
    if ((n & 1) == 0 && cnt > 0) { printf("NO\n"); return 0; }
    if ((n & 1) == 1 && cnt > 1) { printf("NO\n"); return 0; }

    if (n & 1) for (int i = 1; i < kS; i++)
        if (S[i].size() & 1){
            swap(S[i], S[kS]);
            break;
        }

    DecideRow(1, 0, n - 1, 0);

    printf("NO\n");

    return 0;
}

Measured memory_bytes: 3772