[英]Maximal value among shortest distances in a matrix
我正在嘗試解決以下問題,但無法開發算法或方法。 我研究了幾個小時並試圖將問題映射到“最短路徑”圖/矩陣問題或動態規划問題,但沒有成功。
給定一個寬度為 w、高度為 h 的網格。 網格的每個單元格代表一個潛在的建築物,我們將在此網格內添加“n”個建築物。 目標是使所有地塊中最遠的地塊盡可能靠近建築物。 給定輸入 n,即要放置在地塊中的建築物數量,確定建築物放置以最小化最遠的空地塊與建築物的距離。 運動僅限於水平和垂直,即不需要對角運動。
例如, w=4, h=4 and n=3
。 最佳的網格放置將任何地段設置在建築物的兩個單位距離內。 這個案例的答案是2。
“0”表示最佳建築物放置,在這種情況下,每個單元格到最近建築物的所有最短距離的最大值為“2”。
1 0 1 2
2 1 2 1
1 0 1 0
2 1 2 1
以上代表了一種最優解,可能還有更多像上面旋轉的陣列的例子。 以上是最佳解決方案,因為在 3 個建築物 (n=3) 中,一個建築物位於索引 (0,1),第二個位於 (2,1),第三個位於 (2,3)。 每次我們水平和/或垂直移動時,周圍的水平和垂直距離都顯示為 1 和 2。 再次注意,不允許對角移動:
1 ← 0 → 1 → 2
↓
2 ← 1 → 2 ← 1
↑ ↑
1 ← 0 → 1 ← 0
↓ ↓
2 ← 1 → 2 ← 1
其他例子:
示例 1)
w=3, h=3, n=2
必須最佳放置兩座建築物(零點)。 這種情況下的最佳計划之一是:
01
11
10
0 → 1
↓
1 1
↑
1 ← 0
Answer: 1
例如,下面的計划在這種情況下不是最優的,因為它的最大最小距離為 2 而不是 1。因此,即使 0 覆蓋三個“1”,將 0 貪婪地放置在索引 (1,0) 上也不起作用" 在這種情況下的位置,而不是上述最佳方案中的兩個位置。
1 → 2
↑
0 → 1
↓ ↑
1 ← 0
例 2)
w=5, h=1, n=1
必須最佳放置一棟建築物(零)。 最優方案之一:
2 ← 1 ← 0 → 1 → 2
Answer: 2
上述場景中的非最優計划示例:
3 ← 2 ← 1 ← 0 → 1
應完成以下功能:
int findMinDist(int w, int h, int n)
{
}
約束:
1<=w,h
w*h <=28
1<=n<=5
n<=w*h
我一直無法編寫任何代碼,因為老實說我無法推斷出解決方案。
如果給定的兩個點是二維矩陣中的固定點,我可以找到兩者之間的距離或最短距離。 但是,在這種情況下,我不知道這兩個點會在哪里? 可以有很多最優解,在每個地方放置0的組合,找到最遠的距離是不可能的,也不可行。 我試圖將它們放在最大數量為 1 的位置(如中間或 w/2),但這似乎也不起作用。 可以將現有算法應用於此問題嗎?
根據給定的約束,矩陣大小 ( w*h ) 不能超過 28,這是一個相當小的數字。 此外, n的最大可能值是 5。根據對組合學的一些了解,我們知道在最壞的情況下,有28 C 5種方法可以從給定的網格中選擇 5 個批次。 該數字評估為 98280,這是一個足夠小的空間,可以通過記憶進行搜索。 由於w*h的最大值是 28,我們可以用一個整數位掩碼來表示整個網格,它與剩余的建築地塊數量將形成我們 DP 的狀態。 為了計算最終狀態的最遠剩余地段,我們使用廣度優先搜索 (BFS),通過使用我們已經建立建築物的所有點初始化隊列。 共享運行速度足夠快的相同代碼https://ideone.com/ix1nh8
int W, H, N;
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, -1, 1};
int calc(int i, int j) {
if(W <= H)
return i + W * j;
return H * i + j;
}
bool get(int bitmask, int i, int j) {
return (bitmask&(1<<calc(i,j)));
}
int bfs(int bitmask) {
int dist[W][H];
memset(dist, -1, sizeof dist);
int maxDist = 0;
queue<pair<int,int>> Q;
for(int i = 0; i < W; i++)
for(int j = 0; j < H; j++)
if(get(bitmask, i, j)) {
dist[i][j] = 0;
Q.push({i, j});
}
assert(Q.size() == N);
while(!Q.empty()) {
int x = Q.front().first;
int y = Q.front().second;
maxDist = max(maxDist, dist[x][y]);
Q.pop();
for(int d = 0; d < 4; d++) {
int newx = x + dx[d];
int newy = y + dy[d];
if(newx >= W || newy >= H || newx < 0 || newy < 0)
continue;
if(dist[newx][newy] == -1) {
dist[newx][newy] = dist[x][y] + 1;
Q.push({newx, newy});
}
}
}
return maxDist;
}
map<pair<int,int>, int> dp;
int solve(int bitmask, int left) {
if(left == 0) {
return bfs(bitmask);
}
if(dp.find({bitmask, left}) != dp.end()) {
return dp[{bitmask, left}];
}
int minDistance = INT_MAX;
for(int i = 0; i < W; i++)
for(int j = 0; j < H; j++)
if(!get(bitmask, i, j)) {
int val = solve((bitmask|(1<<calc(i, j))), left-1);
minDistance = min(minDistance, val);
}
return dp[{bitmask, left}] = minDistance;
}
沒有位掩碼且需要通過將位置傳遞給遞歸調用來記憶的 Java 解決方案
class MaximumShortestDist
{
static int[] dx = new int[]{1, -1, 0, 0};
static int[] dy = new int[]{0, 0, -1, 1};
public static void main(String[] args) {
System.out.println(findMinDist(14,2,5));
}
static int findMinDist(int w, int h, int n)
{
int[][] grid = new int[w][h];
for(int i=0;i<w;i++)
Arrays.fill(grid[i],-1);
return solve(n,w,h,0,0,grid);
}
static int bfs(int W, int H, int[][] grid) {
int[][] dist = new int[W][H];
for(int i=0;i<W;i++)
for(int j=0;j<H;j++)
dist[i][j] = grid[i][j];
int maxDist = 0;
Queue<Location> Q = new LinkedList<>();
for(int i = 0; i < W; i++)
for(int j = 0; j < H; j++)
if(dist[i][j] == 0){
Q.add(new Location(i,j));
}
while(!Q.isEmpty()) {
int x = Q.peek().first;
int y = Q.peek().second;
maxDist = Math.max(maxDist, dist[x][y]);
Q.poll();
for(int d = 0; d < 4; d++) {
int newx = x + dx[d];
int newy = y + dy[d];
if(newx >= W || newy >= H || newx < 0 || newy < 0)
continue;
if(dist[newx][newy] == -1) {
dist[newx][newy] = dist[x][y] + 1;
Q.add(new Location(newx, newy));
}
}
}
return maxDist;
}
static int solve(int left, int W, int H, int row, int col,int[][] grid) {
if(left == 0) {
return bfs(W,H,grid);
}
int r = row,c=col;
if(col >= H) {
r += col/H;
c = col%H;
}
int minDistance = Integer.MAX_VALUE;
for(int i=r;i<W;i++){
for(int j=c;j<H;j++) {
//Mark Building locations in the recursive call.
grid[i][j] = 0;
int val = solve(left-1, W, H,i,j+1,grid);
minDistance = Math.min(minDistance, val);
// Remove the building
grid[i][j] = -1;
}
}
return minDistance;
}
}
class Location {
int first;
int second;
Location(int x, int y) {
first = x;
second = y;
}
}
看看這個簡單的python程序。
def findMinDistance(w, h, n):
def maxDist(w,h,p):
arr = [[-1]*h for i in range(w)]
q = collections.deque()
for x in p:
r,c = x//h, x%h
arr[r][c] = 0
q.append((r,c,0))
maxd = -1
while len(q):
x,y,d = q.popleft()
maxd = max(maxd, d)
if 0 <= x+1 < w and arr[x+1][y] == -1:
arr[x+1][y] = d+1
q.append((x+1,y,d+1))
if 0 <= x-1 < w and arr[x-1][y] == -1:
arr[x-1][y] = d+1
q.append((x-1,y,d+1))
if 0 <= y+1 < h and arr[x][y+1] == -1:
arr[x][y+1] = d+1
q.append((x,y+1,d+1))
if 0 <= y-1 < h and arr[x][y-1] == -1:
arr[x][y-1] = d+1
q.append((x,y-1,d+1))
return maxd
ans = 100000
pos = [i for i in range(w*h)]
for p in list(itertools.combinations(pos, n)):
ans = min(ans, maxDist(w,h,p))
return ans
沒有按位運算的 Java 代碼。
import javafx.util.Pair;
import java.util.*;
class Office_N {
// W for width, H for height, N for no of offices to build
int W, H, N;
// dx and dy value together gives (x,y)
// which helps to move in 4 adjacent cells
// Right (1,0)
// Left (-1,0)
// Down (0,1)
// Up (0,-1)
int[] dx = {1, -1, 0, 0};
int[] dy = {0, 0, 1, -1};
Map<String, Integer> dp = new HashMap<>();
int[][] grid;
// Constructor will set the values and clear the hashmap.
public Office_N(int w, int h, int n) {
W = w;
H = h;
N = n;
dp.clear();
grid = new int[W][H];
for (int[] r : grid) {
Arrays.fill(r, 0);
}
}
// We convert the 2D array of W*H into 1D array in Row Order (if square matrix or Width is less),
// or Column Wise (if Height is less)
// BitMask holds the bits 0 empty spots, and 1 for where offices are present
// Left means how many offices are still left to be built
public int solve(int[][] grid, int left) {
// If no more offices are left to be built, get the maximum distance for this scenario
if (left == 0) {
return bfs(grid);
}
StringBuilder k = new StringBuilder();
for (int i = 0; i < W; i++) {
for (int j = 0; j < H; j++) {
if (grid[i][j] == 1) {
k.append(i + ":" + j + "::");
}
}
}
k.append("#" + left);
// if the current scenario along with offices left are already processed, return the result
String key = k.toString();
if (dp.containsKey(key)) {
return dp.get(key);
}
int[][] gridtemp = new int[W][H];
for (int i = 0; i < W; i++) {
for (int j = 0; j < H; j++) {
gridtemp[i][j] = grid[i][j];
}
}
// We are trying every possible scenario to build offices in the given grid
int minDist = Integer.MAX_VALUE;
for (int i = 0; i < W; i++) {
for (int j = 0; j < H; j++) {
// If no office present in (i,j)th location, put one office there and check the minimum distance for that scenario
if (gridtemp[i][j] == 0) {
gridtemp[i][j] = 1;
int val = solve(gridtemp, left - 1);
minDist = Math.min(minDist, val);
gridtemp[i][j] = 0;
}
}
}
// Store the min distance possible for the current scenario
dp.put(key, minDist);
return minDist;
}
// This function gives the maximum distance from all the empty spots to the offices for a given case of scenario
private int bfs(int[][] grid) {
// get a distance matrix with initial values as -1
int[][] dist = new int[W][H];
for (int[] row : dist)
Arrays.fill(row, -1);
int maxDist = 0;
// Queue for processing the cells in Bredth-First-Search order.
Queue<Pair<Integer, Integer>> Q = new LinkedList<>();
// if office is present at (i,j)th location, the distance is 0, and put the (i,j) pair in Queue
for (int i = 0; i < W; i++) {
for (int j = 0; j < H; j++) {
if (grid[i][j] == 1) {
dist[i][j] = 0;
Q.add(new Pair<>(i, j));
}
}
}
while (!Q.isEmpty()) {
Pair<Integer, Integer> kv = Q.poll();
int x = kv.getKey();
int y = kv.getValue();
// Get maximum distance for (i,j)th location
maxDist = Math.max(maxDist, dist[x][y]);
// Process all adjacent cells
for (int d = 0; d < dx.length; d++) {
int xNew = x + dx[d];
int yNew = y + dy[d];
// if the adjacent cell is within grid boundary, and is not yet processed,
// set the max dist of he adjacent cell 1 more than the (i,j)th cell
// add the adjacent cell to queue
if (xNew >= 0 && xNew < W && yNew >= 0 && yNew < H && dist[xNew][yNew] == -1) {
dist[xNew][yNew] = dist[x][y] + 1;
Q.add(new Pair<>(xNew, yNew));
}
}
}
return maxDist;
}
public static void main(String[] args) {
Office_N ofc = new Office_N(4, 4, 3);
int res = ofc.solve(ofc.grid, ofc.N);
System.out.println(res);
}
}
我使用數學方法來實現解決方案。
最短距離來自網格中最佳占用分區。 這意味着每個分區的差異的最大值為1
。 以w=4, h=4 and n=3
為例。 在這個網格中,內部有 16 個節點。 對於建築物的每個占用面積,我們可以通過w*h/n = 16/3 = 5.33...
。 這意味着該區域的最大節點數是天花板數A = Math.ceil(w*h/n) = 6
。
由上面的計算,每個分區只有一個節點,所以我們可以假設這個建築物位於中心。 然后我們可以計算出從建築物到邊緣的最長距離是Math.sqrt(A) = 2.45
。 上限數為3
。 由於它是從零開始的,我們可以減去 1 得到2
。
1
:我們可以使用比上面簡單得多的其他數學計算來解決。
這是我的 C++ 版本的解決方案。 我已經測試了Build Offices Google Doc 中的所有測試用例,並且可以正常工作。 挑戰似乎非常可怕; 然而,如果你發現w*h <= 28
描述有問題,它就會變成一個非常簡單的問題。 因此,我只需要使用深度優先搜索列出所有0
和廣度優先搜索的情況來找到訪問整個地圖的最短路徑,完成:)你可以在評論中找到更多細節,祝你好運。
#include <bits/stdc++.h>
using namespace std;
int w, h, n;
vector<int> dirx = {0, 0, 1, -1};
vector<int> diry = {1, -1, 0, 0};
int maxdistance = INT_MAX;
// help convert (x, y) to decimal-based position
int calc(int x, int y) {
return (w * x) + y;
}
// check whether out of bound and visited before in bfs
bool check_valid(int x, int y, unordered_set<int> visited) {
if(x < 0 || x >= h)
return false;
if(y < 0 || y >= w)
return false;
if(visited.count(calc(x, y)))
return false;
return true;
}
// level-ordered bfs and each time find the longest path on map
int bfs(vector<vector<int>> map,
vector<pair<int, int>> start_point) {
int local_max = 0;
queue<pair<int, int>> q;
unordered_set<int> visited;
for(auto s : start_point) {
q.push(s);
visited.insert(calc(s.first, s.second));
}
int dist = 0;
while(!q.empty()) {
int sz = q.size();
dist++;
for(int i = 0; i < sz; i++) {
pair<int, int> head = q.front();
q.pop();
for(int i = 0; i < 4; i++) {
pair<int, int> neighbor = make_pair(head.first + dirx[i], head.second + diry[i]);
if(check_valid(neighbor.first, neighbor.second, visited)) {
map[neighbor.first][neighbor.second] = dist;
visited.insert(calc(neighbor.first, neighbor.second));
q.push(neighbor);
}
}
}
}
// after visiting the whole map
// find the maxdistance
for(int i = 0; i < h; i++) {
for(int j = 0; j < w; j++) {
if(map[i][j] > local_max)
local_max = map[i][j];
}
}
return local_max;
}
// list all the cases for starting point: 0
// in fact, not all the cases
// I considered optimal start point would show up in each distance of (w*h/n)
void dfs(vector<vector<int>> map,
int d,
int n_,
int n,
vector<pair<int, int>> start_point) {
if(n_ == n) {
// cout << "Map: " << '\n';
/**
for(int i = 0; i < map.size(); i++) {
for(int j = 0; j < map[i].size(); j++) {
cout << map[i][j] << ' ';
}
cout << '\n';
}
cout << "distance?: ";**/
if(bfs(map, start_point) < maxdistance) {
maxdistance = bfs(map, start_point);
cout << maxdistance << '\n';
}
return;
}
for(int i = 0; i < d; ++i) {
int pos = n_ * d + i;
map[pos / w][pos % w] = 0;
start_point[n_].first = pos / w;
start_point[n_].second = pos % w;
dfs(map, d, n_ + 1, n, start_point);
map[pos / w][pos % w] = INT_MAX;
start_point[n_].first = -1;
start_point[n_].second = -1;
}
}
int main() {
cin >> w >> h >> n;
int d = (w*h)/n; // build one office in each d distance
vector<vector<int>> map(h, vector<int>(w, INT_MAX));
vector<pair<int, int>> start_point(n, make_pair(-1, -1));
dfs(map, d, 0, n, start_point);
cout << "Max distance of one of optimal solution is: " << maxdistance << '\n';
return 0;
}
我嘗試使用 python 解決這個問題。 答案的核心在於我的 step 函數,它獲取 W x H 網格中 N 建築物的所有可能位置,並將結果作為列表給出。 列表中的每個位置都是 W*i + H 處的位置。 即 2x2 中的位置被視為 0、1、2、3。
# generator function to give each building position
# in a W x H grid
def step(W, H, N):
dim = W * H
slots = [n for n in range(N)]
slots_temp = list(slots)
persist = list(slots)
last = [dim - n for n in slots]
last = last[::-1]
while slots != [0] * N:
yield slots
for i in range(len(slots)-1,-1,-1):
slots[i]+=1
if slots[i] >= last[i] :
slots[i] = 0
else:
while i < len(slots)-1:
slots[i+1] = slots[i] + 1
i+=1
break
# converts a ixj to a step
# assumes W <= H
def get_step(i, j, W , H):
return (i * W) + j
# does bfs from each building position
# and gets the maximum distance
def bfs(step,W,H):
dist = [[-1]*H for i in range(W)]
queue = []
dx = [1,-1,0,0]
dy = [0,0,1,-1]
for i in range(W):
for j in range(H):
step_val = get_step(i, j, W, H)
if step_val in step:
dist[i][j] = 0
queue.append((i,j))
max_val = 0
while len(queue) != 0:
i,j = queue.pop(0)
max_val = max(max_val, dist[i][j])
for _dx,_dy in zip(dx,dy):
new_i,new_j = i + _dx, j + _dy
if new_i < 0 or new_i >= W or new_j <0 or new_j >= H:
continue
if dist[new_i][new_j] == -1:
dist[new_i][new_j] = dist[i][j] + 1
queue.append((new_i,new_j))
return max_val
# calls each posible position of the building
# and computes the minimum distance of all
def main(W, H, N ):
min_val = float('inf')
if W > H:
W, H = H, W
s = step(W, H, N)
for slot in s:
b = bfs(slot, W, H)
min_val = min(min_val, b)
return min_val
main(4, 4, 2)
用於此的 Ruby 代碼
class MaximumShortestDist
def findMinDist(w, h, n)
grid = Array.new(w){Array.new(h)}
for i in 0...w do
grid[i].fill(-1)
end
solve(n,w,h,0,0,grid);
end
def bfs(ww, hh, grid)
dx = [1, -1, 0, 0];
dy = [0, 0, -1, 1];
dist = Array.new(ww){Array.new(hh)};
for i in 0...ww do
for j in 0...hh do
dist[i][j] = grid[i][j];
end
end
maxDist = 0;
qu = Array.new
for i in 0...ww do
for j in 0...hh do
if dist[i][j] == 0
qu.push(Location.new(i,j));
end
end
end
while !qu.empty?
x = qu.first.first;
y = qu.first.second;
maxDist = [maxDist, dist[x][y]].max;
qu.shift;
for d in 0...4 do
newx = x + dx[d];
newy = y + dy[d];
next if newx >= ww || newy >= hh || newx < 0 || newy < 0
if dist[newx][newy] == -1
dist[newx][newy] = dist[x][y] + 1;
qu.push(Location.new(newx, newy));
end
end
end
return maxDist;
end
def solve(left, ww, hh, row, col, grid)
return bfs(ww,hh,grid) if left == 0
r = row
c=col
if col >= hh
r += col/hh;
c = col%hh;
end
minDistance = 999;
for i in r...ww do
for j in c...hh do
grid[i][j] = 0;
val = solve(left-1, ww, hh,i,j+1,grid);
minDistance = [minDistance, val].min;
grid[i][j] = -1;
end
end
return minDistance;
end
end
class Location
attr_reader :first, :second
def initialize(x, y)
@first = x;
@second = y;
end
end
puts MaximumShortestDist.new.findMinDist(2,3,2)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.