#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>

using namespace std;

#define FOR(i,k,n) for(int i=(k); i<(int)(n); ++i)
#define REP(i,n) FOR(i,0,n)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)

template<class T> void debug(T begin, T end){ for(T i = begin; i != end; ++i) cerr<<*i<<" "; cerr<<endl; }
inline bool valid(int x, int y, int W, int H){ return (x >= 0 && y >= 0 && x < W && y < H); }

typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
struct UnionFind{
  int data[10000];
  UnionFind(int N){
    REP(i, N) data[i] = i;
  }
  int root(int x){
    if(data[x] == x) return x;
    return data[x] = root(data[x]);
  }
  void uni(int x, int y){
    x = root(x); y = root(y);
    data[y] = x;
  }
};
struct Edge{
  int src, dst, cost;
  Edge(int a, int b, int c) : src(a), dst(b), cost(c) {}
  bool operator < (const Edge& e) const {
    return cost < e.cost;
  }
};

int main(){
  int S, D;
  while(cin >> S >> D && S){
    vector<Edge> edges;
    REP(i, S){
      REP(j, D){
        int c; cin >> c;
        if(c != 0) edges.push_back(Edge(D, j, c));
      }
    }
    for(int i = 0; i < D; i++){
      for(int j = 1; i + j < D; j++){
        int c; cin >> c;
        if(c != 0) edges.push_back(Edge(i, i + j, c));
      }
    }
    sort(edges.begin(), edges.end());
    int ans = 0;
    UnionFind uf(D + 1);
    FORIT(e, edges){
      int u = e->src, v = e->dst, c = e->cost;
      if(uf.root(u) == uf.root(v)){
      }else{
        uf.uni(u, v);
        ans += c;
      }
    }
    cout << ans << endl;
  }
  return 0;
}