Oil Well
Difficulty: Hard

Mr. Road Runner bought a piece of land in the middle of a desert for a nominal amount. It turns out that the piece of land is now worth millions of dollars as it has an oil reserve under it. Mr. Road Runner contacts the ACME corp to set up the oil wells on his land. Setting up oil wells is a costly affair and the charges of setting up oil wells are as follows. 

The rectangular plot bought by Mr. Road Runner is divided into *r* * *c* blocks. Only some blocks are suitable for setting up the oil well and these blocks have been marked. ACME charges nothing for building the first oil well. For every subsequent oil well built, the cost would be the maximum **ACME distance** between the new oil well and the existing oil wells. 

If *(x,y)* is the position of the block where a new oil well is setup and *(x1, y1)* is the position of the block of an existing oil well, the *ACME distance* is given by 

    max(|x-x1|, |y-y1|)

the maximum *ACME distance* is the maximum among all the *ACME distance* between existing oil wells and new wells. 

If the distance of any two adjacent blocks (horizontal or vertical) is considered 1 unit, what is the minimum cost *(E)* in units it takes to set up oil wells across all the marked blocks?


Input Format:
The first line of the input contains two space separated integers *r* *c*.  
*r* lines follow each containing *c* space separated integers.   
1 indicates that the block is suitable for setting up an oil well, whereas 0 isn't. 

    r c  
    M11 M12 ... M1c  
    M21 M22 ... M2c  
    ...  
    Mr1 Mr2 ... Mrc  


Output Format:
Print the minimum value E as the answer. 


Sample Input:
    3 4
    1 0 0 0
    1 0 0 0
    0 0 1 0


Sample Output:
	3  


Python 3 starter code:
#
# Complete the 'oilWell' function below.
#
# The function is expected to return an INTEGER.
# The function accepts 2D_INTEGER_ARRAY blocks as parameter.
#

def oilWell(blocks):
    # Write your code here



Editorial: November 2020 Editorial: Oil Well
<style id="MathJax_SVG_styles">.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%}
.MathJax_SVG .MJX-monospace {font-family: monospace}
.MathJax_SVG .MJX-sans-serif {font-family: sans-serif}
.MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0}
.MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none}
.mjx-svg-href {fill: blue; stroke: blue}
</style><svg style="display: none;"><defs id="MathJax_SVG_glyphs"></defs></svg><h3>A General Idea</h3>

<p>The solution is based on this:
After setting up k points, only the minimal rectangle covering all the existing points is of importance to us. Start with K = 0, 1, 2 .. etc. and progress.   </p>

<p><strong>Why is this the case?</strong>  </p>

<p>1) For the points inside the rectangle which have not yet been set up, the cost for setting up those is fixed: the sum of the maximum distance between each of them to the edge of the rectangle.     </p>

<p>2) For the points outside the rectangle, the maximum distance will only be dependent on the points in this rectangle, because the oil wells inside that rectangle cannot be a a greater distance.  </p>

<p>So let us start with this easy Dynamic Programming function, by using the above mentioned rule inductively:   </p>

<p>Let F(lx, ly, rx, ry) be the cost of setting up all the oil wells inside rectangle with top-left corner at coordinates (lx, ly) and bottom-right corner at coordinates (rx, ry). </p>

<p>F(lx, ly, rx, ry) = min(F(lx', ly', rx', ry') + cost_of_points_not_set_up) </p>

<p>n &lt;= 50 <br>
The upper bound on the number of points is O(n ^ 2).  </p>

<p>There are n ^ 4 states, and we need to enumurate (lx', ly', rx', ry') which will be done O(n ^ 4) times, and we need to calculate the cost which can be done in O(n ^ 2) time, so the total complexity is O(n ^ 10).  </p>

<h3>How do we optimize this?&gt;</h3>  

<p>As we can see, if there are at least one point strictly between (lx, ly, rx, ry) and (lx', ly', rx', ry'), the cost will not be optimal. So, we add the inner points first before expanding the rectangle.  </p>

<p>Here is the rule we will enforce: 
While adding a new point, the new rectangle can not contain any point which is strictly inside it. </p>

<p>So the choice of (lx', ly', rx', ry') will be restricted. And we can calculate the cost of the new points in O(n). So the complexity can be optimized to O(n ^ 4) * O(n) = O(n ^ 5).  </p>

<h3>Solution:</h3>  

<pre><code>#include &lt;cmath&gt;
#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
using namespace std;

const int inf = 1000000000;
const int N = 52;
int dp[N][N][N][N], a[N][N];

int ab(int x) {
    return (x &gt; 0)?x:(-x);
}

int dis(int x1,int y1,int x2,int y2) {
    return max(ab(x1 - x2), ab(y1 - y2));
}

int cal(int x,int y,int x1,int y1,int x2, int y2) {
    return max(dis(x,y,x1,y1), dis(x,y,x2,y2));
}


int main() {
    /* Enter your code here. Read input from STDIN. Print output to STDOUT */  
    int m, n;
    scanf("%d%d",&amp;m,&amp;n);
    for (int i = 0; i &lt; m; ++i) {
        for (int j = 0; j &lt; n; ++j) {
            scanf("%d",&amp;a[i][j]);
        }
    }
    for (int i = m - 1; i &gt;= 0; --i) {
        for (int j = n - 1; j &gt;= 0; --j) {
            for (int k = i; k &lt; m; ++k) {
                for (int h = (k == i)?(j + 1):j; h &lt; n; ++h) {
                    dp[i][j][k][h] = inf;

                    if (i &lt; k) {
                        int may = dp[i + 1][j][k][h]; 
                        for (int y = j; y &lt;= h; ++y) {
                            if (a[i][y]) {
                                may += cal(i, y, i + 1, j, k, h);
                            }

                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);
                        may = dp[i][j][k - 1][h];
                        for (int y = j; y &lt;= h; ++y) {
                            if (a[k][y]) {
                                may += cal(k, y, i ,j, k - 1, h);

                            }
                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);
                    }
                    if (j &lt; h) {
                        int may = dp[i][j + 1][k][h];
                        for (int x = i; x &lt;= k; ++x) {
                            if (a[x][j]) {
                                may += cal(x, j, i, j + 1, k, h);
                            }
                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);
                        may = dp[i][j][k][h - 1];
                        for (int x = i; x &lt;= k; ++x) {
                            if (a[x][h]) {
                                may += cal(x, h, i, j, k, h - 1);
                            }
                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);

                    }

                }
            }
        }
    }
    printf("%d\n",dp[0][0][m - 1][n - 1]);
    return 0;
}
</code></pre>

Reference solution (C++):
###C++  
```cpp  
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
    
const int inf = 1000000000;
const int N = 52;
int dp[N][N][N][N], a[N][N];
    
int ab(int x) {
    return (x > 0)?x:(-x);
}
    
int dis(int x1,int y1,int x2,int y2) {
    return max(ab(x1 - x2), ab(y1 - y2));
}
    
int cal(int x,int y,int x1,int y1,int x2, int y2) {
    return max(dis(x,y,x1,y1), dis(x,y,x2,y2));
}
    
    
int main() {
    /* Enter your code here. Read input from STDIN. Print output to STDOUT */  
    int m, n;
    scanf("%d%d",&m,&n);
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            scanf("%d",&a[i][j]);
        }
    }
    for (int i = m - 1; i >= 0; --i) {
        for (int j = n - 1; j >= 0; --j) {
            for (int k = i; k < m; ++k) {
                for (int h = (k == i)?(j + 1):j; h < n; ++h) {
                    dp[i][j][k][h] = inf;
                   
                    if (i < k) {
                        int may = dp[i + 1][j][k][h]; 
                        for (int y = j; y <= h; ++y) {
                            if (a[i][y]) {
                                may += cal(i, y, i + 1, j, k, h);
                            }
                        
                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);
                        may = dp[i][j][k - 1][h];
                        for (int y = j; y <= h; ++y) {
                            if (a[k][y]) {
                                may += cal(k, y, i ,j, k - 1, h);
                            
                            }
                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);
                    }
                    if (j < h) {
                        int may = dp[i][j + 1][k][h];
                        for (int x = i; x <= k; ++x) {
                            if (a[x][j]) {
                                may += cal(x, j, i, j + 1, k, h);
                            }
                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);
                        may = dp[i][j][k][h - 1];
                        for (int x = i; x <= k; ++x) {
                            if (a[x][h]) {
                                may += cal(x, h, i, j, k, h - 1);
                            }
                        }
                        dp[i][j][k][h] = min(dp[i][j][k][h], may);
                        
                    }
                    
                }
            }
        }
    }
    printf("%d\n",dp[0][0][m - 1][n - 1]);
    return 0;
}
```