#include <iostream>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <vector>
#include <valarray>
#include <array>
#include <queue>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <complex>
#include <random>
#include <bitset>

using namespace std;
using ll = long long;
using ull = unsigned long long;
using P = pair<int, int>;

/**
 * ????????????
 */

template <int V>
struct Bridge {
    vector<int> g[V];
    void add(int a, int b) {
        g[a].push_back(b);
        g[b].push_back(a);
    }

    int imos[V]; //0????????°(i, root[i])??????
    bool used[V];
    int root[V], dps[V];
    void dfs(int i, int b, int dp) {
        root[i] = b;
        dps[i] = dp;
        used[i] = true;
        for (int d: g[i]) {
            if (used[d]) {
                if (dps[i] < dps[d]) {
                    imos[i]--;
                    imos[d]++;
                }
            } else {
                dfs(d, i, dp+1);
            }
        }
    }

    int dfs2(int i) {
        used[i] = true;
        for (int d: g[i]) {
            if (used[d]) continue;
            imos[i] += dfs2(d);
        }
        return imos[i];
    }

    void exec(int v = V) {
        fill_n(imos, v, 0);
        fill_n(root, v, -1);
        fill_n(dps, v, 0);
        fill_n(used, v, false);
        for (int i = 0; i < v; i++) {
            if (used[i]) continue;
            dfs(i, -1, 0);
        }
        fill_n(used, v, false);
        for (int i = 0; i < v; i++) {
            if (root[i] != -1) continue;
            dfs2(i);
        }
    }
};

/**
 * QuickFind
 *
 * See_Also: http://topcoder.g.hatena.ne.jp/iwiwi/20131226/1388062106
 */
template <int N>
struct UnionFind {
    int ig[N];
    vector<int> gi[N];
    int gn;

    void init(int n = N) {
        for (int i = 0; i < n; ++i) {
            ig[i] = i;
            gi[i] = {i};
        }
        gn = n;
    }

    void merge(int a, int b) {
        if (same(a, b)) return;
        gn--;
        int x = ig[a], y = ig[b];
        if (gi[x].size() < gi[y].size()) swap(x, y);
        for (int j: gi[y]) {
            ig[j] = x;
        }
        gi[x].insert(gi[x].end(), gi[y].begin(), gi[y].end());
        gi[y].clear();
    }

    bool same(int a, int b) {
        return ig[a] == ig[b];
    }

    int group_num() {
        return gn;
    }
};


const int MN = 110;
Bridge<MN> br;
UnionFind<MN> uf;

int n, m;

int w[MN];
vector<int> g[MN];

int dsm = 0;

int dfs(int p, int b, int ns) {
    dsm += ns * w[p];
    int sz = w[p];
    for (int d: g[p]) {
        if (d == b) continue;
        sz += dfs(d, p, ns+w[p]);
    }
    return sz;
}

int solve() {
    int ma = -1;
    for (int i = 0; i < n; i++) {
        if (!w[i]) continue;
        dsm = 0;
        vector<int> v;
        for (int j: g[i]) {
            v.push_back(dfs(j, i, w[i]));
        }
        const int MN = 120;
        bool dp[MN] = {};
        dp[0] = true;
//        printf("st\n");
        for (int d: v) {
//            printf("%d\n", d);
            for (int k = MN-1; k >= d; k--) {
                dp[k] |= dp[k-d];
            }
        }
//        printf("ed\n");
        int r = 0;
        for (int k = 0; k < MN; k++) {
            if (!dp[k]) continue;
//            printf("ok! %d %d\n", k, n-w[i]);
            r = max(r, k*(n-w[i]-k));
        }
//        printf("rrr %d %d\n", i, r);
//        printf("dfs %d %d\n", i, dfs(i, -1, 0));
        ma = max(ma, dsm+r);
//        ma = max(ma, dfs(i, -1, 0));
    }
    return ma;
}

int main() {
    cin >> n >> m;
    map<string, int> mp;
    for (int i = 0; i < n; i++) {
        string s;
        cin >> s;
        mp[s] = i;
    }
    for (int i = 0; i < m; i++) {
        string s, t;
        cin >> s >> t;
//        printf("%d %d\n", mp[s], mp[t]);
        br.add(mp[s], mp[t]);
    }
    br.exec(n);
    uf.init(n);
    for (int i = 0; i < n; i++) {
        if (br.root[i] == -1) continue;
        if (br.imos[i] == 0) continue;
        uf.merge(i, br.root[i]);
    }
    int sm = 0;
    for (int i = 0; i < n; i++) {
        w[i] = (int)uf.gi[i].size();
        sm += w[i]*w[i];
//        printf("%d %d\n", i, w[i]);
    }
    for (int i = 0; i < n; i++) {
        if (br.root[i] == -1) continue;
        if (br.imos[i] != 0) continue;
        int x = uf.ig[i], y = uf.ig[br.root[i]];
//        printf("ng %d %d\n", x, y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    cout << sm + solve() << endl;
    return 0;
}

Measured memory_bytes: 3256