// ???????????????
#include<vector>
#include<map>
#include<queue>
#include<tuple>
#include<functional>
// ?????????
  const int NIL = -1;
  const double INF = 1e9;
class MinimumCostFlow {
private:
  struct Edge {
    int from, to;
    double weight, capacity;
    Edge() {}
    Edge(int f, int t, double w, double c) : from(f), to(t), weight(w), capacity(c) {}
    bool operator<(const Edge& e) const {return from < e.from;}
  };
public:
  void insert(int f, int t, double w, double c);
  double PrimalDual(int source, int sink, int n) const;
private:
  std::map<int, std::vector<Edge>> edge_;
};
// ????????????
void MinimumCostFlow::insert(int f, int t, double w, double c) {
  edge_[f].emplace_back(f, t, w, c);
  edge_[t].emplace_back(t, f, -w, 0);
}
// ????°??????¨??? O(????????? * (E + V log V))
double MinimumCostFlow::PrimalDual(int source, int sink, int n) const {
  std::map<int, std::map<int, double>> flow;
  std::map<int, double> distance;
  double result = 0;
  while(true) {
    // source ?????? Dijkstra
    std::map<int, double> difference;
    std::map<int, Edge> via;
    typedef std::tuple<double, Edge> Node;
    std::priority_queue<Node, std::vector<Node>, std::greater<Node>> q;
    q.emplace(0, Edge(source, source, 0, 0));
    while(!q.empty()) {
      double dif;
      Edge edge;
      std::tie(dif, edge) = q.top();
      q.pop();
      int prev = edge.from;
      int current = edge.to;
      if(difference.count(current)) continue;
      difference[current] = dif;
      via[current] = edge;
      if(edge_.count(current)) for(const auto& e: edge_.at(current)) {
        double residue = e.capacity - flow[e.from][e.to];
        double d = e.weight + distance[e.from] - distance[e.to];
        if(residue > 0) q.emplace(dif + d, e);
      }
    }
    // ???????????¢?????´??°
    for(auto d: difference) distance[d.first] += d.second;
    // sink ?????§?????????????????¨??????????????°??????
    if(!via.count(sink)) break;
    // ?????????????????????????????????
    double add = INF;
    for(int v = sink; v != via[v].from; v = via[v].from) add = std::min(add, via[v].capacity - flow[via[v].from][via[v].to]);
    for(int v = sink; v != via[v].from; v = via[v].from) {
      flow[via[v].from][via[v].to] += add;
      flow[via[v].to][via[v].from] -= add;
      result += add * via[v].weight;
    }
    n -= add;
    if(n == 0) return result;
  }
  return -1;
}

#include<bits/stdc++.h>
using namespace std;

vector<int> memo(9);
int pow3(int n) {return memo[n] ? memo[n] : (memo[n] = (n < 1 ? 1 : 3 * pow3(n - 1)));}

int main() {
  int D, K, L;
  while(cin >> D >> K >> L, D | K | L) {
    vector<vector<int>> c(D, vector<int>(K));
    for(auto& i: c) for(auto& j: i) cin >> j;
    int M, N, P;
    cin >> M >> N >> P;
    vector<vector<int>> r(M, vector<int>(K));
    for(auto& i: r) for(auto& j: i) cin >> j;
    vector<vector<int>> t(P, vector<int>(K));
    for(auto& i: t) for(auto& j: i) cin >> j;

    const int INF = 1e9;
    vector<vector<vector<int>>> dp(D + 1, vector<vector<int>>(pow3(K), vector<int>(L + 1, INF)));
    dp[0][0][0] = 0;
    for(int day = 0; day < D; ++day) for(int ternary = 0; ternary < pow3(K); ++ternary) for(int bought = 0; bought <= L; ++bought) {
      dp[day + 1][ternary][0] = min(dp[day + 1][ternary][0], dp[day][ternary][bought]);
      if(bought == L) continue;
      for(int part = 0; part < K; ++part) {
        int owned = (ternary / pow3(part)) % 3;
        if(2 <= owned) continue;
        dp[day][ternary + pow3(part)][bought + 1] = min(dp[day][ternary + pow3(part)][bought + 1], dp[day][ternary][bought] + c[day][part]);
      }
    }

//     for(int ternary = 0; ternary < pow3(K); ++ternary) for(int bought = 0; bought <= L; ++bought) {
//       for(int i = 0; i < K; ++i) cout<<((ternary / pow3(i)) % 3);
//       cout<<": "<<dp[2][ternary][bought]<<endl;
//     }

    MinimumCostFlow graph;
    int no_bag = P + M;
    int source = P + M + 1;
    int sink = P + M + 2;
    graph.insert(source, no_bag, 0, INF);
    for(int i = 0; i < P; ++i) graph.insert(source, i, 0, 1);
    for(int j = 0; j < M; ++j) graph.insert(P + j, sink, 0, 1);
    for(int j = 0; j < M; ++j) {
      int need = 0;
      for(int part = 0; part < K; ++part) need += pow3(part) * r[j][part];
      if(dp[D][need][0] != INF) graph.insert(no_bag, P + j, dp[D][need][0], 1);
      for(int i = 0; i < P; ++i) {
        int remain = need;
        for(int part = 0; part < K; ++part) {
          if(r[j][part] - t[i][part] < 0) {remain = -1; break;}
          remain -= pow3(part) * t[i][part];
        }
        if(~remain) if(dp[D][remain][0] != INF) graph.insert(i, P + j, dp[D][remain][0], 1);
      }
    }

    cout << graph.PrimalDual(source, sink, N) << endl;
  }
}

Measured memory_bytes: 14260