首页 > 试题广场 >

建物流中转站

[编程题]建物流中转站
  • 热度指数:8696 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

Shopee物流会有很多个中转站。在选址的过程中,会选择离用户最近的地方建一个物流中转站。

假设给你一个二维平面网格,每个格子是房子则为1,或者是空地则为0。找到一个空地修建一个物流中转站,使得这个物流中转站到所有的房子的距离之和最小。 能修建,则返回最小的距离和。如果无法修建,则返回 -1。


若范围限制在100*100以内的网格,如何计算出最小的距离和?

当平面网格非常大的情况下,如何避免不必要的计算?


输入描述:
4
0 1 1 0
1 1 0 1
0 0 1 0
0 0 0 0

先输入方阵阶数,然后逐行输入房子和空地的数据,以空格分隔。


输出描述:
8

能修建,则返回最小的距离和。如果无法修建,则返回 -1。
示例1

输入

4
0 1 1 0
1 1 0 1
0 0 1 0
0 0 0 0

输出

8
示例2

输入

4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

输出

-1
import java.util.*;
public class Main{
    public static void main(String[] args){
        // 空间复杂度 O(2n),时间复杂度O(n*n)
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int count1=0;
        int[][] tem1 = new int[n*n][2];//储存 数组值 =1的位置
        int count2=0;
        int[][] tem2 = new int[n*n][2];//储存 数组值 =0的位置
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                int a= sc.nextInt();
                if(a==0) {
                    tem2[count2][0]=i;
                    tem2[count2][1]=j;
                    count2++;
                }
                if(a==1) {
                    tem1[count1][0]=i;
                    tem1[count1][1]=j;
                    count1++;
                }
            }
        }
        if(count1==0) {System.out.println(0);return;}
        if(count2==0){System.out.println(-1);return;}
        int min=0;
        for(int i=0;i<count2;i++){//数组值 =0的位置
            int tem=0;
            for(int j=0;j<count1;j++){//数组值 =1的位置
                tem += Math.abs(tem2[i][0]-tem1[j][0])+Math.abs(tem2[i][1]-tem1[j][1]);
            }
            if(i==0) min=tem;
            else
            min = Math.min(min,tem);
        }
        System.out.println(min);
        
    }
}
发表于 2022-01-08 14:32:46 回复(0)
记录所有的空地位置和每行每列房子的个数,然后遍历空地,计算其到所有行和列房子的距离,选择出最小的就行
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[][] grid = new int[n][n];
        int[][] onesCnt = new int[2][n];    // 第一行是每行1的个数,第二行是每列1的个数
        ArrayList<int[]> startPoints = new ArrayList<>();
        for(int i = 0; i < n; i++){
            String[] row = br.readLine().split(" ");
            for(int j = 0; j < n; j++){
                int val = Integer.parseInt(row[j]);
                if(val == 1){
                    onesCnt[0][i] ++;
                    onesCnt[1][j] ++;
                }else{
                    startPoints.add(new int[]{i, j});
                }
            }
        }
        // 没有空地直接返回-1
        if(startPoints.isEmpty()){
            System.out.println(-1);
        }else{
            int minDis = Integer.MAX_VALUE;
            for(int[] point: startPoints){      // 以当前位置为中转站位置
                int curDis = 0;
                for(int i = 0; i < n; i++){
                    curDis += Math.abs(i - point[0]) * onesCnt[0][i];     // 距离为abs(i-point[0])的点有onesCnt[0][i]个
                    curDis += Math.abs(i - point[1]) * onesCnt[1][i];
                }
                minDis = Math.min(minDis, curDis);
            }
            System.out.println(minDis);
        }
    }
}
scala版
import scala.io.StdIn
import scala.collection.mutable.ListBuffer

object Main {
    def main(args: Array[String]): Unit = {
        val n = StdIn.readInt
        val freeSpace = ListBuffer[Array[Int]]()
        val onesCnt = Array.ofDim[Int](2, n)
        for(i <- 0 until n){
            val row = StdIn.readLine.split(" ")
            for(j <- 0 until n){
                if(row(j) == "1"){
                    onesCnt(0)(i) += 1
                    onesCnt(1)(j) += 1
                }else
                    freeSpace.append(Array[Int](i, j))
            }
        }
        if(freeSpace.isEmpty){
            println(-1)
        }else{
            var minDis = Integer.MAX_VALUE
            for(pos: Array[Int] <- freeSpace){
                var curDis = 0
                for(i <- 0 until n)
                    curDis += math.abs(i - pos(0)) * onesCnt(0)(i) + math.abs(i - pos(1)) * onesCnt(1)(i)
                minDis = math.min(minDis, curDis)
            }
            println(minDis)
        }
    }
}

编辑于 2021-09-08 16:23:41 回复(0)
import java.util.*;
public class Main{
    public static void main(String[] strs){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            int n = Integer.valueOf(sc.nextLine());
            int[][] house = new int[n][n];
            for(int i =0;i<n;i++){
                String[] str = sc.nextLine().split(" ");
                for(int j=0;j<n;j++){
                    house[i][j] = Integer.valueOf(str[j]);
                }
            }
            //表示是不是全1,是的话flag为1,有0则为0
            int flag = 1;
            int min = Integer.MAX_VALUE;
            int sum = 0;
            for(int i =0;i<n;i++){
                for(int j =0;j<n;j++){
                    if(house[i][j]==1){
                        continue;
                    }else
                    {
                        flag = 0;
                        min = getDistance(min,house,i,j);
                    }
                }
            }
            if(flag==1)min = -1;
            System.out.println(min);
        }
    }
    public static int getDistance(int min,int[][] house,int i,int j){
        int sum = 0;
        int n = house[0].length;
        for(int k=0;k<n;k++){
            for(int l =0;l<n;l++){
                if(house[k][l]==0){
                    continue;
                }else{
                    if(k>i){sum+=(k-i);}
                    else{sum+=(i-k);}
                    if(l>j){sum+=(l-j);}
                    else{sum+=(j-l);}
                }
            }
        }
        
        return sum<min?sum:min;
    }
}
暴力Java循环
发表于 2020-06-03 11:28:48 回复(0)
/*
大致思路就是建立一个辅助数组result[n][n] 表示每个点的结果。
main方法遍历数组,
若[i][j]为1,result[i][j]设为Integer MAX再调用findZero方法 从i,j开始往后寻找0并计算距离结果累加放入result[i][j].
若[i][j]为0就调用finOne方法从i,j开始往后寻找1并计算距离累加都放入放入起点处的result[i][j].
main方法的2层循环结束,再从result中找最小的.
*/

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int [][] q = new int[n][n];                                     //问题数组
        int [][] result = new int[n][n];                              //结果数组
        for(int i=0; i < n; i++){
            for(int j=0; j < n; j++){
                q[i][j] = sc.nextInt();
                result[i][j] = 0;
            }
        }
        sc.close();
        
        for(int i=0; i < n; i++){
            for(int j=0; j < n; j++){
                if(q[i][j] == 0){
                    findOne(q, result, i, j, n);                             //碰到0就往后面找1
                }else{
                    result[i][j] = Integer.MAX_VALUE;
                    findZero(q, result,i, j, n);                              //否则就找0
                }
            }
        }
        
        int minResult = Integer.MAX_VALUE;
        
        for(int i=0; i < n; i++){
            for(int j=0; j < n; j++){
                if(result[i][j] < minResult){
                    minResult = result[i][j];
                }
            }
        }
        minResult = minResult == Integer.MAX_VALUE ? -1: minResult;
        System.out.println(minResult);
    }

    private static void findZero(int[][] q, int[][] result, int x, int y, int n) {
        int j = y;
        for(int i=x; i < n; i++){
            for(; j < n; j++){
                if(q[i][j] == 0){
                    result[i][j] += (Math.abs(i - x) + Math.abs(j - y));   //把距离分散到碰到的0上面
                }
            }
            j = 0;
        }

        
    }

    private static void findOne(int[][] q, int[][] result, int x, int y, int n) {
        int j = y;
        for(int i=x; i < n; i++){
            for(; j < n; j++){
                if(q[i][j] == 1){
                    result[x][y] += (Math.abs(i - x) + Math.abs(j - y)); //把距离累加到 result[x][y]上
                }
            }
            j = 0;
        }
        
    }

}

发表于 2019-08-01 17:56:24 回复(0)