web-dev-qa-db-fra.com

Valeur maximale parmi les distances les plus courtes dans une matrice

J'essaie de résoudre le problème suivant et je n'ai pas pu développer d'algorithme ou d'approche. J'ai fait des recherches pendant quelques heures et j'ai essayé de faire correspondre le problème au problème de graphique/matrice "Shortest Path" ou à des problèmes de programmation dynamique, mais je n'y suis pas parvenu.

Étant donné une grille avec w comme largeur, h comme hauteur. Chaque cellule de la grille représente un terrain à bâtir potentiel et nous ajouterons "n" bâtiments à l'intérieur de cette grille. L'objectif est que le plus éloigné de tous les lots soit aussi proche que possible d'un bâtiment. Étant donné une entrée n, qui est le nombre de bâtiments à placer dans le lot, déterminez l'emplacement du bâtiment pour minimiser la distance entre le lot vide le plus éloigné et le bâtiment. Le mouvement est limité à l'horizontale et à la verticale, c'est-à-dire qu'un mouvement diagonal n'est pas requis.

Par exemple, w=4, h=4 and n=3. Un placement de grille optimal fixe tout terrain à moins de deux unités de distance du bâtiment. La réponse pour ce cas est 2.

"0" indique le placement optimal du bâtiment et dans ce cas, la valeur maximale de toutes les distances les plus courtes au bâtiment le plus proche pour chaque cellule est "2".

1 0 1 2
2 1 2 1
1 0 1 0
2 1 2 1

Ce qui précède représente une solution optimale, il pourrait y avoir plus comme le tableau ci-dessus tourné comme exemple. Ce qui précède est une solution optimale car sur les 3 bâtiments (n = 3), un bâtiment a été placé à l'indice (0,1), le deuxième a été placé à (2,1) et le troisième a été placé à (2,3). La distance horizontale et verticale environnante est indiquée par 1 et 2 en ajoutant 1 chaque fois que nous nous déplaçons horizontalement et/ou verticalement. Notez à nouveau que le mouvement diagonal n'est pas autorisé:

1 ← 0 → 1 → 2
    ↓
2 ← 1 → 2 ← 1
    ↑       ↑
1 ← 0 → 1 ← 0
    ↓       ↓
2 ← 1 → 2 ← 1

Autres exemples:

Exemple 1)

w=3, h=3, n=2

Deux bâtiments (zéros) doivent être placés de manière optimale. L'un des plans optimaux pour ce cas est:

01
11
10

0 → 1
↓
1   1
    ↑  
1 ← 0

Answer: 1

Par exemple, le plan suivant ne sera pas optimal dans ce cas car il a la plus petite distance maximale comme 2 au lieu de 1. Donc, placer 0 avec gourmandise à l'index (1,0) ne fonctionne pas même si le 0 couvre trois "1 "positions dans ce cas au lieu de deux comme dans le scénario optimal ci-dessus.

1 → 2
↑
0 → 1
↓   ↑   
1 ← 0

Exemple 2)

w=5, h=1, n=1

Un bâtiment (zéros) doit être placé de manière optimale. Un des plans optimaux:

2 ← 1 ← 0 → 1 → 2

Answer: 2

Exemple d'un plan non optimal dans le scénario ci-dessus:

3 ← 2 ← 1 ← 0 → 1

La fonction ci-dessous doit être remplie:

int findMinDist(int w, int h, int n)
{

}

Contraintes:

1<=w,h
w*h <=28
1<=n<=5
n<=w*h

Je n'ai pas pu écrire de code car honnêtement je n'ai pas pu déduire la solution.

Si les deux points donnés sont des points fixes dans une matrice 2D, je peux trouver la distance ou la distance la plus courte entre les deux. Mais, dans ce cas, je ne sais pas où seront les deux points? Il peut y avoir de nombreuses solutions optimales et placer des combinaisons de 0 à chaque endroit et trouver la distance la plus éloignée n'est pas possible et ne sera pas faisable. J'ai essayé de les placer à des positions qui donnent un maximum de 1 (comme au milieu ou avec 2) mais cela ne semble pas fonctionner aussi. Un algorithme existant pourrait-il être appliqué à ce problème?

7
Stacky

Conformément à la contrainte donnée, la taille de la matrice ( w * h) ne peut pas dépasser 28, ce qui est assez petit. De plus, la valeur maximale possible pour n est 5. De peu de connaissances en combinatoire, nous savons qu'il y a 28C5 façons de sélectionner 5 lots de la grille donnée au pire des cas. Le chiffre correspond à 98280, ce qui est un espace suffisamment petit pour effectuer une recherche avec mémorisation. Étant donné que la valeur maximale pour w * h est 28, nous pouvons représenter la grille entière dans un masque de bits entier qui, avec le nombre de lots de construction restant à configurer, formera les états de notre DP. Pour calculer le lot restant le plus éloigné pour l'état final, nous utilisons une recherche de largeur en premier (BFS) en initialisant la file d'attente avec tous les points où nous avons configuré un bâtiment. Partager le code pour le même qui fonctionne suffisamment rapidement 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;
}
7
nellex

Solution Java sans masque de bits et besoin de mémorisation en passant les positions aux appels récursifs

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;
    }
}
3
Harish

Le code Java pour cela sans les opérations au niveau du bit.

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
Denim Datta

J'ai essayé de résoudre cette question en utilisant python. Le cœur de la réponse réside dans ma fonction de pas, qui obtient toutes les positions possibles des N bâtiments dans une grille L x H et donne le résultat sous forme de liste. Chaque position dans la liste est l'emplacement à W * i + H.C'est-à-dire que les positions dans un 2x2 sont traitées comme 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)