#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
#include <ctime>
#include <queue>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define sz(X) ((int)(X).size())
#define FOREACH(i,c) for(__typeof(c.begin()) i=(c.begin());i!=(c).end();++i)
#define IN(_lower,_variable,_higher) (((_lower)<=(_variable)) && ((_variable)<=(_higher)))
#define REP(i,n) for(int i=0;i<(n);++i)
#define FORU(v,p,k) for(int v=p;v<k;++v)
#define FORD(v,p,k) for(int v=(p)-1;v>=k;--v)
#define FORLLU(v,p,k) for(LL v=p;v<k;++v)
#define FORLLD(v,p,k) for(LL v=(p)-1;v>=k;--v)
template<class T> vector<T> tokenize_to(const string &str) { vector<T> r; T x; istringstream is(str); while (is >> x) r.push_back(x); return r; }
#define junik(X) {sort( (X).begin(), (X).end() ); (X).erase( unique( (X).begin(), (X).end() ), (X).end() ); }
#define min(x,y) (((x)<(y))?(x):(y))
#define max(x,y) (((x)>(y))?(x):(y))
#define MAXV 1e20
double best [100][100];
int c[100][100];
int f[100][100];
class state{
public:
int x, y;
double t;
state(int _x, int _y, double _t){
x=_x; y=_y; t=_t;
}
const bool operator<(const state &drugi) const {
if (x<drugi.x) return true;
if (x>drugi.x) return false;
if (y<drugi.y) return true;
if (y>drugi.y) return false;
if (t<drugi.t) return true;
if (t>drugi.t) return false;
return true;
}
const bool operator==(const state &drugi) const {
return (x==drugi.x && y==drugi.y && t == drugi.t);
}
};
queue<state> q;
vector<state> start;
int h, m, n;
int outOfGrid(int x, int y) {
return (x<0 || y<0 || x>=n || y>=m);
}
bool tryToGo(int c1, int f1, int c2, int f2, int h){
if (h+50>c2) return false;
if (f1+50>c2) return false;
if (f2+50>c2) return false;
if (f2+50>c1) return false;
return true;
}
void updateStart(state current) {
for (int i=-1;i<2;i+=2)
for (int j=-1;j<2;j+=2) {
if (!outOfGrid(current.x+i, current.y+j) && tryToGo(c[current.x][current.y], f[current.x][current.y], c[current.x+i][current.y+j], f[current.x+i][current.y+j],h ) ) {
start.push_back(state(current.x+i, current.y+j, 0));
}
}
}
double getF(int x, int y, double t) {
return min(f[x][y], h-t*0.1);
}
double getT(int x, int y, double goalF) {
if (f[x][y]>goalF) return -1;
return (h-goalF)*10;
}
double cost(state current, int xNew, int yNew) {
int c1 = c[current.x][current.y];
int c2 = c[xNew][yNew];
int f1Min=c2-50;
int f2Min=c1-50;
double t1 = getT(current.x, current.y, f1Min);
double t2 = getT(xNew, yNew, f2Min);
if (t1 == -1 || t2 == -1) return -1;
t1 = max (t1, t2);
double ret=0;
if (t1>=current.t) ret = 1;
if (getF(current.x, current.y, t1) - f[current.x][current.y]<20) ret+=10;
return ret;
}
double solve() {
double ret=0;
scanf("%d %d %d", &h, &n, &m);
for (int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d ", &c[i][j]);
for (int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d ", &f[i][j]);
for (int i=0;i<n;i++)
for(int j=0;j<m;j++)
best[i][j]=MAXV;
start.clear();
start.push_back(state(0,0,0));
best[0][0]=0;
int nTemp=0;
do {
nTemp = sz(start);
FOREACH(x, start) {
updateStart(*x);
}
junik(start);
} while (sz(start)!=nTemp);
while (sz(q)>0) {
state current=q.front();
q.pop();
for (int i=-1;i<2;i+=2)
for (int j=-1;j<2;j+=2) {
if (!outOfGrid(current.x+i, current.y+j)) {
double c = cost(current, current.x+i, current.y+j);
if (c==-1) continue;
if (c+current.t<best[current.x+i][current.y+j]) {
q.push(state(current.x+i, current.y+j, current.t+c));
best[current.x+i][current.y+j]=c+current.t;
}
}
}
}
ret = best[n-1][m-1];
return ret;
}
int main() {
int _n=0;
scanf("%d ", &_n);
vector<double> sols;
for (int i=0;i<2;i++) {
sols.push_back(solve());
}
for (int i=0;i<sz(sols);i++) {
printf("Case #%d: %0.6lf\n", i+1, sols[i]);
}
return 0;
}