#include <iostream>
#include <climits>
#include <queue>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <cstdio>
#include <cstdlib>

using namespace std;

#define reep(i,f,n) for(int i=f; i<int(n); ++i)
#define rep(i,n) reep(i,0,n)

typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> pii;

struct Data
{
	int len;
	int num;
	Data(int len, int num) : len(len), num(num) {}
	bool operator< (const Data& d)const
	{
		return len > d.len;
	}
};

int main()
{
	int s, d;
	while(scanf("%d%d", &s, &d), s||d){
		int n = s+d;
		vvi dist(n, vi(n, INT_MAX/3));
		rep(i, s) rep(j, d){
			int di;
			scanf("%d", &di);
			if(di)
				dist[i][s+j] = dist[s+j][i] = di;
		}
		rep(i, d-1) rep(j, d-i-1){
			int di;
			scanf("%d", &di);
			if(di)
				dist[s+i][s+i+j+1] = dist[s+i+j+1][s+i] = di;
		}
		
		priority_queue<Data> Q;
		vi visited(n, 0);
		int connect = 0;
		int sum = 0;
		
		rep(i, s)
			Q.push(Data(0, i));
		
		while(connect < d){
			Data d = Q.top();
			Q.pop();
			if(visited[d.num])
				continue;
			//printf("d.num = %d, len = %d\n", d.num, d.len);
			visited[d.num] = 1;
			connect += d.num >= s;
			sum += d.len;
			rep(i, n){
				if(!visited[i]){
					Data next(dist[d.num][i], i);
					Q.push(next);
				}
			}
		}
		
		printf("%d\n", sum);
	}
	
	return 0;
}