#include <bits/stdc++.h>
using namespace std;
inline int in() {
  int x;
  scanf("%d", &x);
  return x;
}
namespace UF {
int par[1000], rank[1000];
void init(int n) {
  int i;
  for ((i) = 0; (i) < (int)(n); (i)++) {
    par[i] = i;
    rank[i] = 0;
  }
}
int find(int x) {
  if (par[x] == x)
    return x;
  else
    return par[x] = find(par[x]);
}
void unite(int x, int y) {
  x = find(x);
  y = find(y);
  if (x == y) return;
  if (rank[x] < rank[y])
    par[x] = y;
  else {
    par[y] = x;
    if (rank[x] == rank[y]) rank[x]++;
  }
}
bool same(int x, int y) { return find(x) == find(y); }
}  // namespace UF
struct Edge {
  int from, to, cost;
  Edge(int from_, int to_, int cost_) {
    from = from_;
    to = to_;
    cost = cost_;
  }
  bool operator<(const Edge& a) const { return cost < a.cost; }
};
int main() {
  int i, j, k;
  int s, d;
  while (scanf("%d %d", &s, &d)) {
    if (s == 0 && d == 0) break;
    vector<Edge> edges;
    for ((i) = 0; (i) < (int)(s); (i)++)
      for ((j) = 0; (j) < (int)(d); (j)++) {
        int t = in();
        if (t == 0) continue;
        edges.push_back(Edge(i, s + j, t));
      }
    for ((i) = 0; (i) < (int)(d - 1); (i)++)
      for (j = i + 1; j < d; j++) {
        int t = in();
        if (t == 0) continue;
        edges.push_back(Edge(s + i, s + j, t));
      }
    sort(edges.begin(), edges.end());
    int ans = 0;
    int n = edges.size();
    UF::init(n);
    for (i = 1; i < s; i++) UF::unite(i, 0);
    for ((i) = 0; (i) < (int)(n); (i)++) {
      if (UF::same(edges[i].from, edges[i].to)) continue;
      ans += edges[i].cost;
      UF::unite(edges[i].from, edges[i].to);
    }
    printf("%d\n", ans);
  }
  return 0;
}
