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

vector<vector<vector<int>>>dp;
vector<string> split(const string &str, char delim) {
	vector<string> res;
	size_t current = 0, found;
	while ((found = str.find_first_of(delim, current)) != string::npos) {
		res.push_back(string(str, current, found - current));
		current = found + 1;
	}
	res.push_back(string(str, current, str.size() - current));
	return res;
}

int getdis(string a, string b) {
	vector<vector<int>>dp(a.size() + 1, vector<int>(b.size() + 1, 1e9));
	dp[0][0] = 0;
	for (int i = 0; i <= a.size(); ++i) {
		for (int j = 0; j <= b.size(); ++j) {
			if(i!=a.size()&&j!=b.size()){
				if (a[i] == b[j]) {
					dp[i + 1][j + 1] = min(dp[i + 1][j + 1], dp[i][j]);
				}
				else {
					dp[i + 1][j + 1] = min(dp[i + 1][j + 1], dp[i][j] + 1);
				}
			}
			if (i != a.size()) {
				dp[i + 1][j] = min(dp[i + 1][j], 1+dp[i][j]);
			}
			if (j != b.size()) {
				dp[i][j + 1] = min(dp[i][j + 1], 1+dp[i][j]);
			}


		}
	}
	return dp[a.size()][b.size()];
}
typedef int Weight;
typedef int Cap;
const Weight W_INF = INT_MAX;
const Weight W_ZERO = 0;
const Cap C_INF = INT_MAX;
const Cap C_ZERO = 0;

struct Edge {
	int src, dst;
	Cap capacity;
	Weight cost;
	Edge(int src, int dst, const Cap& acap, const Weight& acost) :
		src(src), dst(dst), capacity(acap), cost(acost) {
	}
};
bool operator < (const Edge &e, const Edge &f) {
	return e.cost > f.cost;
}
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;


#define RESIDUE(s,t) (capacity[s][t]-flow[s][t])
#define RCOST(u,v) (cost[u][v] + h[u] - h[v])

//??°?????????????????§???????????????????????¨?????????

//Graph &ag
//????????§???????????????(u, v, capacity, cost) ??????????????????(u, v, 0, -cost) ???????????°????????????????????¶?????????????????§????´???°????????§???????????°???????????????
//int s, int t
//?????????????§??????¨?????????
//?????????
//?????¨??¨????????????????????????
pair<Weight, Cap> minimumCostFlow(const Graph &ag, int s, int t) {
	//check???????´???°??????????????£???????????????
	Graph g(ag);
	for (int i = 0; i < ag.size(); ++i) {
		for (int j = 0; j < ag[i].size(); ++j) {
			int d = ag[i][j].dst;
			int s = ag[i][j].src;

			bool ok = false;
			for (int k = 0; k < ag[d].size(); ++k) {
				if (ag[d][k].src == s) {
					ok = true;
					break;
				}
			}
			if (!ok) {
				g[d].push_back(Edge(d, s, C_ZERO, -ag[i][j].cost));
			}
		}
	}
	const int n = g.size();
	vector<vector<Cap>> capacity(n, vector<Cap>(n)), flow(n, vector<Cap>(n));
	vector<vector<Weight>>cost(n, vector<Weight>(n));
	for (int u = 0; u < n; ++u) {
		for (auto e : g[u]) {
			capacity[e.src][e.dst] = capacity[e.src][e.dst] + e.capacity;
			cost[e.src][e.dst] = cost[e.src][e.dst] + e.cost;
		}
	}
	pair<Weight, Cap> total; // (cost, flow)
	vector<Weight> h(n);

	for (Cap F = C_INF; F > 0; ) { // residual flow
		vector<Weight> d(n, W_INF); d[s] = W_ZERO;
		vector<int> p(n, -1);
		priority_queue<Edge> Q; // "e < f" <=> "e.cost > f.cost"
		for (Q.push(Edge(-2, s, C_ZERO, W_ZERO)); !Q.empty(); ) {
			Edge e = Q.top(); Q.pop();
			if (p[e.dst] != -1) continue;
			p[e.dst] = e.src;
			for(auto f:g[e.dst]){
				if (RESIDUE(f.src, f.dst) > 0) {
					if (d[f.dst] > d[f.src] + RCOST(f.src, f.dst)) {
						d[f.dst] = d[f.src] + RCOST(f.src, f.dst);
						Q.push(Edge(f.src, f.dst, 0, d[f.dst]));
					}
				}
			}
		}
		if (p[t] == -1) {
			break;
		}

		Cap f = F;
		for (int u = t; u != s; u = p[u]) {
			f = min(f, RESIDUE(p[u], u));
		}
		for (int u = t; u != s; u = p[u]) {
			total.first = total.first + f * cost[p[u]][u];
			flow[p[u]][u] = flow[p[u]][u] + f; flow[u][p[u]] = flow[u][p[u]] - f;
		}
		F = F - f;
		total.second = total.second + f;
		for (int u = 0; u < n; ++u) {
			h[u] = h[u] + d[u];
		}
	}
	return total;
}
void add_edge(Graph&g, const int from, const int to, const Cap& cap, const Weight& weight) {
	assert(weight >= 0);//????????¨?????°??????
	g[from].push_back(Edge(from, to, cap, weight));
}
int main() {
	int N, M; cin >> N >> M;
	map<string, int>mp;
	string st; getline(cin, st);
	while (N--) {
		getline(cin, st);
		auto v(split(st, ' '));
		for (auto c : v) {
			mp[c]++;
		}
	}
	vector<string>dict;
	for (int i = 0; i < M; ++i) {
		string st; cin >> st;
		dict.push_back(st);
	}
	const int start = 0;
	const int dic_start = 1;
	const int mp_start = dic_start + dict.size();
	const int goal = mp_start + mp.size();
	Graph g(goal + 1);
	for (int i = 0; i < dict.size(); ++i) {
		add_edge(g, start, dic_start + i, 1, 0);
	}
	for (int i = 0; i < dict.size(); ++i) {
		int j = 0;
		for(auto m:mp){
			add_edge(g, dic_start + i, mp_start + j, 1, getdis(dict[i], m.first)*m.second);
			j++;
		}
	}
	{
		int j = 0;
		for (auto m : mp) {
			add_edge(g, mp_start + j,goal, 1, 0);
			j++;
		}
	}
	auto ans = minimumCostFlow(g, start, goal);
	int num = ans.first;
	cout << num << endl;
	return 0;
}

Measured memory_bytes: 21836