#include <stdio.h>
#include <string.h>
#include <queue>
#include <functional>
#include <deque>
#include <algorithm>
using namespace std;
#define MAXN 2048
#define MAXM 1048576
struct Node {
int x, y, cap;
double cost;
int next;
} edge[MAXM];
class MinCost {
public:
int e, head[MAXN], pre[MAXN], record[MAXN], inq[MAXN];
int dis[MAXN];
int n;
const int INF = 0x3f3f3f3f;
void Addedge(int x, int y, int cap, int cost) {
edge[e].x = x, edge[e].y = y, edge[e].cap = cap, edge[e].cost = cost;
edge[e].next = head[x], head[x] = e++;
edge[e].x = y, edge[e].y = x, edge[e].cap = 0, edge[e].cost = -cost;
edge[e].next = head[y], head[y] = e++;
}
pair<int, int> mincost(int s, int t) {
int mncost = 0;
int flow, totflow = 0;
int i, x, y;
while(1) {
for (int i = 0; i < n; i++)
dis[i] = INF;
int oo = dis[0];
dis[s] = 0;
deque<int> Q;
Q.push_front(s);
while(!Q.empty()) {
x = Q.front(), Q.pop_front();
inq[x] = 0;
for(i = head[x]; i != -1; i = edge[i].next) {
y = edge[i].y;
if(edge[i].cap > 0 && dis[y] > dis[x] + edge[i].cost) {
dis[y] = dis[x] + edge[i].cost;
pre[y] = x, record[y] = i;
if(inq[y] == 0) {
inq[y] = 1;
if(Q.size() && dis[Q.front()] > dis[y])
Q.push_front(y);
else
Q.push_back(y);
}
}
}
}
if(dis[t] == oo)
break;
flow = 0x3f3f3f3f;
for(x = t; x != s; x = pre[x]) {
int ri = record[x];
flow = min(flow, edge[ri].cap);
}
for(x = t; x != s; x = pre[x]) {
int ri = record[x];
edge[ri].cap -= flow;
edge[ri^1].cap += flow;
edge[ri^1].cost = -edge[ri].cost;
}
totflow += flow;
mncost += dis[t] * flow;
}
return make_pair(mncost, totflow);
}
void init(int n) {
this->n = n;
e = 0;
for (int i = 0; i <= n; i++)
head[i] = -1;
}
} g;
int readDouble() {
static char s[16];
scanf("%s", s);
if (s[0] == '-') return -1;
int i, x = 0;
for (i = 0; s[i] && s[i] != '.'; i++)
x = x * 10 + s[i] - '0';
if (!s[i]) return x * 100;
i++;
x = x * 10 + s[i] - '0';
if(!s[i+1]) return x * 10;
i++;
x = x * 10 + s[i] - '0';
return x;
}
int main() {
int N, M, Nsz[64], Msz[64], cases = 0;
int NMp[64][64];
while (scanf("%d %d", &N, &M) == 2 && N) {
for (int i = 0; i < N; i++)
scanf("%d", &Nsz[i]);
for (int i = 0; i < M; i++)
scanf("%d", &Msz[i]);
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
NMp[i][j] = readDouble();
int source = N + M, sink = N + M + 1;
g.init(N + M + 2);
for (int i = 0; i < N; i++)
g.Addedge(source, i, Nsz[i], 0);
for (int i = 0; i < M; i++)
g.Addedge(i + N, sink, Msz[i], 0);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (NMp[i][j] < 0) continue;
g.Addedge(i, j + N, 0x3f3f3f3f, NMp[i][j]);
}
}
pair<int, int> ret1 = g.mincost(source, sink);
g.init(N + M + 2);
for (int i = 0; i < N; i++)
g.Addedge(source, i, Nsz[i], 0);
for (int i = 0; i < M; i++)
g.Addedge(i + N, sink, Msz[i], 0);
const int ADD = 50 * 100 * 2000;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (NMp[i][j] < 0) continue;
g.Addedge(i, j + N, 0x3f3f3f3f, ADD - NMp[i][j]);
}
}
pair<int, int> ret2 = g.mincost(source, sink);
double r1, r2;
r1 = ret1.first / 100.0;
r2 = (ret2.second * ADD - ret2.first) / 100.0;
printf("Problem %d: ", ++cases);
printf("%.2lf to %.2lf\n", r1, r2);
}
return 0;
}