#include <bits/stdc++.h>
#define rep(i,n) for(int i=0; i<(n); i++)
#define chmin(a,b) a = min(a,b)
#define chmax(a,b) a = max(a,b)
using namespace std;
using ll = long long;
using vi = vector<ll>;
using vv = vector<vi>;
using P  = pair<ll,int>;//(cost,to)
using vP = vector<P>;
using vvP= vector<vP>;

const int INF = 1001001001;

void dijkstra(vvP &graph, vi &cost, int &s){
    
    priority_queue<P, vP, greater<P>> q;
    q.push(P(0,s));
    
    vector<bool> used((int)graph.size(), 0);
    
    while(!q.empty()){
        ll c  = q.top().first;
        int v  = q.top().second;
        q.pop();
        
        if(used[v])continue;
        if(c>cost[v])continue;
        used[v] = 1;
        cost[v] = c;
        
        for(int i=0; i<(int)graph[v].size(); i++){
            if(used[graph[v][i].second])continue;
            q.push(P(c + graph[v][i].first, graph[v][i].second));
        }
    }
    return;
}

int main(){
    int r, c;
    cin >> r >> c;
    vv a(r, vi(c-1));
    vv b(r-1, vi(c));
    rep(i,r)rep(j,c-1)cin >> a[i][j];
    rep(i,r-1)rep(j,c)cin >> b[i][j];
    
    vvP graph(r*c*2);
    
    rep(i,r)rep(j,c){
        if(i)graph[i*c+j].push_back(P(2, (i-1)*c+j + r*c));
        if(i!=r-1)graph[i*c+j].push_back(P(b[i][j], (i+1)*c+j));
        if(j)graph[i*c+j].push_back(P(a[i][j-1], i*c+j-1));
        if(j!=c-1)graph[i*c+j].push_back(P(a[i][j], i*c+j+1));
        
        if(i)graph[i*c+j+r*c].push_back(P(1, (i-1)*c+j + r*c));
        if(i!=r-1)graph[i*c+j+r*c].push_back(P(b[i][j], (i+1)*c+j));
        if(j)graph[i*c+j+r*c].push_back(P(a[i][j-1], i*c+j-1));
        if(j!=c-1)graph[i*c+j+r*c].push_back(P(a[i][j], i*c+j+1));
    }
    
    vi cost(r*c*2, INF);
    int s = 0;
    
    dijkstra(graph, cost, s);
    
    cout << cost[r*c-1] << endl;
    
    return 0;
}
#include <bits/stdc++.h>

template <typename T>
T next() {
    T temp; std::cin >> temp;
    return temp;
}

template <>
int next() {
    int temp; scanf("%d", &temp);
    return temp;
}
template <>
long long next() {
    long long temp; scanf("%lld", &temp);
    return temp;
}
template <>
double next() {
    double temp; scanf("%lf", &temp);
    return temp;
}
template <>
float next() {
    float temp; scanf("%f", &temp);
    return temp;
}

template <typename T1, typename T2>
std::pair<T1, T2> next() {
    std::pair<T1, T2> temp;
    temp.first = next<T1>();
    temp.second = next<T2>();
    return temp;
}

template <typename T>
std::vector<T> next(int n) {
    std::vector<T> temp(n);
    for(int i = 0; i < n; i++)
        temp[i] = next<T>();
    return temp;
}

template <typename T1, typename T2>
std::vector<std::pair<T1, T2>> next(int n) {
    std::vector<std::pair<T1, T2>> temp(n);
    for(int i = 0; i < n; i++)
        temp[i] = next<T1, T2>();
    return temp;
}

template <typename T>
void print(const T &x, char endc = '\n') {
    std::cout << x << endc;
    return;
}
void print(const int &x, char endc = '\n') {
    printf("%d%c", x, endc);
    return;
}
void print(const long long &x, char endc = '\n') {
    printf("%lld%c", x, endc);
    return;
}
void print(const size_t &x, char endc = '\n') {
    printf("%zu%c", x, endc);
    return;
}
void print(const float &x, char endc = '\n') {
    printf("%f%c", x, endc);
    return;
}
void print(const double &x, char endc = '\n') {
    printf("%lf%c", x, endc);
    return;
}

template<typename T1, typename T2>
void print(const std::pair<T1, T2> &p, char sepc = ' ', char endc = '\n') {
    print(p.first, sepc);
    print(p.second, endc);
    return;
}

template<typename T>
void print(const std::vector<T> &v, char sepc = ' ', char endc = '\n') {
    for(const T &e : v) print(e, sepc);
    printf("%c", endc);
    return;
}




template<typename T>
class SparseGraph {
    struct Node {
        std::vector<std::pair<int, T>> adj;
        T value;
    };

private:
    std::vector<Node> nodes;
    int nodeSize;
    int edgeSize = 0;

public:
    SparseGraph(int n) {
        nodes.resize(n);
        nodeSize = n;
    }

    SparseGraph(const std::vector<T> &values) {
        int n = values.size();
        nodes.resize(n);
        nodeSize = n;
        for(int i = 0; i < n; i++)
            nodes[i].value = values[i];
    }

    void addEdge(int u, int v, const T &edgeVal = 0) {
        nodes[u].adj.push_back({v, edgeVal});
        edgeSize++;
    }

    const int &getNodeSize() const {
        return nodeSize;
    }

    const int &getEdgeSize() const {
        return edgeSize;
    }

    const T &valueOf(int here) const {
        return nodes[here].value;
    }

    const std::vector<std::pair<int, T>> &adjOf(int here) const {
        return nodes[here].adj;
    }
};



using namespace std;

double solve(int connected, int disconnected, vector<double> &memo) {
    if(disconnected == 0)
        return 0.0;
    
    double &ret = memo[connected];
    if(!ret) {
        ret = solve(connected+1, disconnected-1, memo) + 1.0 + 1.0*connected/disconnected;
    }

    return ret;
}

void eachTC() {
    int N = next<int>();
    vector<double> memo(N, 0.0);
    double res = solve(1, N-1, memo);
    printf("%.9lf", res);
}

int main() {
    constexpr bool multipleTC = false;
    int T = multipleTC ? next<int>() : 1;
    while(T--) eachTC();

    return 0;
}
