#include<iostream>
#include<tuple>
#include<vector>
#include<algorithm>
using namespace std;
// ------ Class ------ //
class UnionFind {
private:
	unsigned size_; std::vector<unsigned> par, rank;
public:
	UnionFind() : size_(0), par(std::vector<unsigned>()), rank(std::vector<unsigned>()) {};
	UnionFind(unsigned size__) : size_(size__) {
		par.resize(size_); rank.resize(size_);
		for (unsigned i = 0; i < size_; i++) par[i] = i, rank[i] = 0;
	}
	unsigned size() { return size_; }
	unsigned root(unsigned x) { return par[x] == x ? x : par[x] = root(par[x]); }
	bool same(unsigned x, unsigned y) { return root(x) == root(y); }
	void unite(unsigned x, unsigned y) {
		x = root(x), y = root(y);
		if (x == y) return;
		if (rank[x] < rank[y]) par[x] = y;
		else if (rank[x] == rank[y]) par[y] = x, rank[x]++;
		else par[y] = x;
	}
	bool operator==(const UnionFind &u) { return par == u.par; }
	bool operator!=(const UnionFind &u) { return par != u.par; }
};
//-----------------Code--------------------
vector<tuple<int, int, int>>tup;
int n, m;
int main() {
	while (true) {
		tup.clear();
		cin >> n >> m; if (n == 0 && m == 0)break;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				int a; cin >> a; if (a >= 1)tup.push_back(make_tuple(a, i, n + j));
			}
		}
		for (int i = 0; i < m; i++) {
			for (int j = i + 1; j < m; j++) {
				int a; cin >> a; if (a >= 1) tup.push_back(make_tuple(a, n + i, n + j));
			}
		}
		sort(tup.begin(), tup.end()); UnionFind UF(n + m);
		for (int i = 0; i < n; i++) {
			for (int j = i + 1; j < n; j++) {
				UF.unite(i, j);
			}
		}
		int cnt = 0, G = 0;
		for (int i = 0; i < tup.size(); i++) {
			int a1 = get<1>(tup[i]), a2 = get<2>(tup[i]);
			if (UF.same(a1, a2) == false) {
				UF.unite(a1, a2); cnt += get<0>(tup[i]); G++;
			}
			if (G == m)break;
		}
		cout << cnt << endl;
	}
	return 0;
}