#ifndef ___Rank_Union_Find
#define ___Rank_Union_Find

#include <vector>

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; }
};

#endif

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct edge { int a, b, cost; };
bool operator<(const edge& e1, const edge& e2) {
	return e1.cost < e2.cost;
}
int n, m, x;
int main() {
	while (cin >> n >> m, n) {
		vector<edge> v;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				cin >> x;
				if(x != 0) v.push_back(edge{ i, n + j, x });
			}
		}
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < m - i - 1; j++) {
				cin >> x;
				if(x != 0) v.push_back(edge{ n + i, n + i + j + 1, x });
			}
		}
		sort(v.begin(), v.end());
		UnionFind uf(n + m);
		for (int i = 0; i < n - 1; i++) uf.unite(i, i + 1);
		int ret = 0;
		for (int i = 0; i < v.size(); i++) {
			if (!uf.same(v[i].a, v[i].b)) {
				uf.unite(v[i].a, v[i].b);
				ret += v[i].cost;
			}
		}
		cout << ret << endl;
	}
	return 0;
}