#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cmath>
using namespace std;

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

typedef int Weight;
struct Edge {
    int src, dst;
    Weight weight;
    Edge(int src, int dst, Weight weight) :
    src(src), dst(dst), weight(weight) { }
};
bool operator < (const Edge &e, const Edge &f) {
    return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!
        e.src != f.src ? e.src < f.src : e.dst < f.dst;
}
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

typedef vector<Weight> Array;
typedef vector<Array> Matrix;

struct UnionFind {
    vector<int> data;
    UnionFind(int size) : data(size, -1) { }
    bool unionSet(int x, int y) {
        x = root(x); y = root(y);
        if (x != y) {
            if (data[y] < data[x]) swap(x, y);
            data[x] += data[y]; data[y] = x;
        }
        return x != y;
    }
    bool findSet(int x, int y) {
        return root(x) == root(y);
    }
    int root(int x) {
        return data[x] < 0 ? x : data[x] = root(data[x]);
    }
    int size(int x) {
        return -data[root(x)];
    }
};

//
const int MAX_N = 51;
int SP[MAX_N][MAX_N];
int DI[MAX_N][MAX_N];

typedef priority_queue <Edge, vector<Edge> > QUEUE;

int main() {
    int s, d;
    while ( cin >> s >> d && s && d ) {
        memset( SP, 0, sizeof(SP) );
        memset( DI, 0, sizeof(DI) );
        for ( int i = 0; i < s; ++ i ) {
            for ( int j = 0; j < d; ++ j ) {
                cin >> SP[i][j];
            }
        }
        for ( int i = 0; i < d - 1; ++ i ) {
            for ( int j = 0; j < d - i - 1; ++ j ) {
                cin >> DI[i][i+j+1];
                DI[i+j+1][i] = DI[i][i+j+1];
            }
        }

        int res = 0;
        QUEUE Q;
        for ( int i = 0; i < s; ++ i ) {
            for ( int j = 0; j < d; ++ j ) {
                if ( SP[i][j] == 0 ) continue;
                Q.push( Edge( i, j + s, SP[i][j] ) );
            }
        }
        for ( int i = 0; i < d; ++ i ) {
            for ( int j = i + 1; j < d; ++ j ) {
                if ( DI[i][j] == 0 ) continue;
                Q.push( Edge( i + s, j + s, DI[i][j] ) );
            }
        }

        UnionFind uf( s + d );
        while ( ! Q.empty() ) {
            Edge e = Q.top();
            Q.pop();

            int a = e.src;
            int b = e.dst;
            if ( uf.findSet( a, b ) ) continue;

            bool f1 = false, f2 = false;
            for ( int i = 0; i < s; ++ i ) {
                if ( uf.findSet( i, a ) ) f1 = true;
                if ( uf.findSet( i, b ) ) f2 = true;
            }

            if ( f1 && f2 ) continue;
            
            int w = e.weight;
            res += w;
            uf.unionSet( a, b );
        }

        cout << res << endl;
    }
    return 0;
}