#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <climits>
#include <set>
#include <sstream>
using namespace std;
#define repn(i,s,n) for (int i=int(s); i < int(n); i++)
#define rep(i,n) repn(i,0,n)
#define repd(i,n) for (int i=int(n)-1; i >= 0; i--)

typedef vector<int> VI;
typedef vector<VI> VVI;
struct Edge {
  int from, to, cost, capacity, revIdx;
};
typedef vector<vector<Edge>> AdjList;

void addEdge(AdjList& g, int from, int to, int cost) {
  Edge e1{from, to, cost, 1, (int)g[to].size()};
  Edge e2{to, from, -cost, 0, (int)g[from].size()};
  g[from].push_back(e1);
  g[to].push_back(e2);
}

int editDistance(const string& a, const string& b) {
  // cout << "start" << endl;
  int n = a.size();
  int m = b.size();
  VVI dp(n+1, VI(m+1));
  rep(i, n+1) dp[i][0] = i;
  rep(j, m+1) dp[0][j] = j;
  rep(i, n+1) rep(j, m+1) {
    if (i*j==0) continue;
    int c = a[i-1] == b[j-1] ? 0 : 1;
    dp[i][j] = min({
      dp[i-1][j] + 1,
      dp[i][j-1] + 1,
      dp[i-1][j-1] + c
    });
  }
  // cout << "end " << a << " "<< b<<": " << dp[n][m] << endl;
  return dp[n][m];
}

const int INF = 100000000;
int minCostFlow(AdjList& g, int s, int t, int f) {
  int gn = g.size();
  int ret = 0;

  auto getDist = [&g,gn,s,t]() -> vector<Edge*> {
    VI dist(gn, INF);
    VI prevv(gn, -1);
    VI preve(gn, -1);
    dist[s] = 0;
    prevv[s] = -2;
    while(true) {
      bool updated = false;
      rep(v, gn) {
        rep (ei, g[v].size()) {
          Edge& e = g[v][ei];
          if (e.capacity > 0 && dist[e.to] > dist[v] + e.cost) {
            dist[e.to] = dist[v] + e.cost;
            prevv[e.to] = v;
            preve[e.to] = ei;
            updated = true;
          }
        }
      }
      if (!updated) break;
    }
    vector<Edge*> path;
    if (dist[t] == INF) return path;
    for (int v = t;; v = prevv[v]) {
      int ei = preve[v];
      if (ei == -1) break;
      path.push_back(&g[prevv[v]][ei]);
    }
    return path;
  };

  while (f > 0) {
    auto path = getDist();
    if (path.empty()) return -1;
    int augedFlow = f;
    for(Edge* e : path) augedFlow = min(augedFlow, e->capacity);
    for(Edge* e : path) {
      e->capacity -= augedFlow;
      g[e->to][e->revIdx].capacity += augedFlow;
      ret += e->cost * augedFlow;
    }
    // cout << f << endl;
    f -= augedFlow;
  }
  return ret;
}

int main() {
  int n, m;
  cin >> n >> m;
  map<string, int> wordcounts;

  cin.ignore();
  rep(i,n) {
    string s;
    getline(cin, s);
    stringstream ss(s);
    while (ss >> s) {
      wordcounts[s]++;
    }
  }
  int numWords = wordcounts.size();
  vector<string> words;
  for(auto& kv : wordcounts) words.push_back(kv.first);
  // cout << words.size() << words[0] << endl;

  vector<string> dict(m);
  rep(i,m) cin >> dict[i];

  int gn = 1 + numWords + m + 1;
  // 0: source
  // 1..numWords: words
  // numWords..numWords + m: dict
  // 1 + numWords + m: termination
  AdjList g(gn);
// cout<<dict[m-1] << "hello2\n";
  rep(i, numWords) {
    addEdge(g, 0, 1 + i, 0);
    int count = wordcounts[words[i]];
    rep(j, m) {
      // cout << "he " << words[i]<<", "<< dict[j] <<endl;
      int dist = editDistance(words[i], dict[j]);
      addEdge(g, 1 + i, 1 + numWords + j, dist * count);
    }
  }
// cout<<"hi\n";
  rep(j, m) addEdge(g, 1 + numWords + j, 1 + numWords + m, 0);

  cout << minCostFlow(g, 0, 1 + numWords + m, numWords) << endl;

  return 0;
}

Measured memory_bytes: 9448