Shopee物流会有很多个中转站。在选址的过程中,会选择离用户最近的地方建一个物流中转站。
假设给你一个二维平面网格,每个格子是房子则为1,或者是空地则为0。找到一个空地修建一个物流中转站,使得这个物流中转站到所有的房子的距离之和最小。 能修建,则返回最小的距离和。如果无法修建,则返回 -1。
若范围限制在100*100以内的网格,如何计算出最小的距离和?
当平面网格非常大的情况下,如何避免不必要的计算?
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。
4 0 1 1 0 1 1 0 1 0 0 1 0 0 0 0 0
8
4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
-1
// 所有1点到达某个0点(x,y)的距离和 = 每行1点的数量 * 行间距 + 每列1点的数量 * 列间距 // 所以我们只需分别记录每行和每列1的数量和所有0点的坐标即可 #include <iostream> #include <vector> #include <limits> using namespace std; int main(){ int n; cin >> n; //分别存储每行的1和每列的1数量 vector<vector<int> > cnts(2, vector<int> (n, 0)); //候选点(0点)的坐标 vector<pair<int, int> > points; int cnt, temp; for(int i = 0; i<n; ++i){ for(int j = 0; j<n; ++j){ cin >> temp; //记录每行和每列的1的数量 if(temp) { ++cnts[0][i]; ++cnts[1][j]; } else{ //将0点的坐标记录到points中 points.push_back(make_pair(i, j)); } } } if(points.empty()){ cout << -1 << endl; } else{ //计算每个0坐标的距离和,得到最大值 int min = numeric_limits<int>::max(), cur_dist; for(auto pnt : points){ cur_dist = 0; //pnt.first横坐标,对应其他行的1之和,表示纵向路径和 //pnt.second纵坐标,对应其他列的1之和,表示横向路径和 for(int i = 0; i<n; ++i){ if(i!=pnt.first) cur_dist += abs(i-pnt.first)*cnts[0][i]; if(i!=pnt.second) cur_dist += abs(i-pnt.second)*cnts[1][i]; } if(cur_dist<min) min = cur_dist; } cout << min << endl; } return 0; }
#include <bits/stdc++.h> using namespace std; struct P{ int x,y; }; int main(){ int n; cin>>n; int G[n][n]; vector<P> a,b; for(int i=0;i<n;i++) for(int j=0;j<n;j++){ cin>>G[i][j]; if(G[i][j]==1) a.push_back(P{i,j}); else b.push_back(P{i,j}); } if(b.size()==0) cout<<-1<<endl; else{ int Min=INT_MAX; for(int i=0;i<b.size();i++){ int s = 0; for(int j=0;j<a.size();j++) s += abs(a[j].x-b[i].x) + abs(a[j].y-b[i].y); Min = min(Min, s); } cout<<Min<<endl; } return 0; }
n^2 做法 二维变一维 先计算x轴上每个点的贡献 然后先计算y轴上每个点的贡献 最后计算每个所有点的贡献,求出最小值。 #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<bits/stdc++.h> using namespace std; int z[1005][1005]; int x[1005]; int y[1005]; int vx[1005],vy[1005]; int main() { // freopen("in","r",stdin); int n; cin>>n; int t; int sum=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ cin>>z[i][j]; if(z[i][j]==1){ x[i]++; y[j]++; sum++; } } } int sumx=0; int numx=0; for(int i=0;i<n;i++){ numx+=(x[i]*(i+1)); } for(int i=0;i<n;i++){ numx-=(sum-sumx); numx+=sumx; vx[i]=numx; sumx+=x[i]; // cout<<vx[i]<<' '<<numx<<' '<<sumx<<endl; } int sumy=0; int numy=0; for(int i=0;i<n;i++){ numy+=(y[i]*(i+1)); } for(int i=0;i<n;i++){ numy-=(sum-sumy); numy+=sumy; vy[i]=numy; sumy+=y[i]; } int maxn=100000000; for(int i=0;i<n;i++ ){ for(int j=0;j<n;j++){ if(z[i][j]==0){ //cout<<vx[i]+vy[j]<<endl; maxn=min(maxn,vx[i]+vy[j]); } } } if(maxn==100000000) cout<<-1<<endl; else cout<<maxn<<endl; return 0; }
def cal_distance(matrix, x_center, y_center): real_x_center, real_y_center = 0, 0 max_distance = n * 2 # 矩阵两点间的最大距离 for i in range(n): # 求在理想中心点附近最近的真实中心点 for j in range(n): if matrix[i][j] == 0: # 当点空时 temp_distance = abs(x_center - i) + abs(y_center - j) if temp_distance < max_distance: # 替换最大距离 max_distance = temp_distance real_x_center, real_y_center = i, j # 替换真实中心点坐标 distance_sum = 0 for i in range(n): for j in range(n): if matrix[i][j] == 1: # 当点有房屋时 distance_sum += abs(real_x_center - i) + abs(real_y_center - j) # 计算距离总和 return distance_sum n = int(input()) matrix = [list(map(int, input().split())) for i in range(n)] x_sum = 0 y_sum = 0 total_house_count = 0 for i in range(n): for j in range(n): if matrix[i][j] == 1: x_sum += i y_sum += j total_house_count += 1 if total_house_count == n * n: print(-1) else: x_center = x_sum / total_house_count # 利用平均值计算出理想中心点 y_center = y_sum / total_house_count print(cal_distance(matrix, x_center, y_center))
//Optimize algorithm by seting poles #include <iostream> #include <vector> #include <utility> #include <algorithm> #include <cmath> using namespace std; const int inf=0x3f3f3f3f; int main(){ int n; cin>>n; vector<vector<int>> grid( n, vector<int>(n,0) ); vector<pair<int,int>> vec; //set limits xl,xr,yu,yd int xl=n-1,xr=0,yu=n-1,yd=0; for(int i=0;i<n;++i){ for(int j=0,tmp;j<n;++j){ cin>>tmp; if(tmp){ grid[i][j]=1; vec.push_back(make_pair(i,j)); if( i<yu) yu=i; if( i>yd) yd=i; if( j<xl) xl=j; if( j>xr) xr=j; } } } //if all elements in the area limited by xl,xr.yu,yd is 1, the solution is outside it yu = max(yu-1, 0); yd = min(yd+1, n-1); xl = max(xl-1 , 0); xr = min(xr+1, n-1); int sum, minlen= inf; for(int u=yu ; u<=yd ; ++u ){ for(int l=xl ; l<=xr; ++l ){ if( grid[u][l]==0 ){ sum=0; for(int i=0;i<vec.size();++i){ sum += abs( vec[i].first-u ) + abs( vec[i].second - l ); } minlen = min(minlen, sum); } } } if(minlen<inf) cout<<minlen; else cout<<-1; return 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) } } }
#include<iostream> #include<stdio.h> #include<queue> #include<vector> #include<limits.h> #include<string> #include<algorithm> #include<math.h> using namespace std; int main() { int n; cin>>n; queue<pair<int,int>> emp; queue<pair<int,int>> house; for(int i=0;i<n;++i) { for(int j=0;j<n;++j) { int x; cin>>x; if(x==1) { house.push(pair<int,int>(i,j)); } else { emp.push(pair<int,int>(i,j)); } } } if(emp.size()==0) { cout<<"-1"<<endl; return 0; } int ans=INT_MAX; while(!emp.empty()) { auto [x,y]=emp.front(); emp.pop(); int count=0; for(int i=house.size();i>0;--i) { auto [a,b]=house.front(); house.pop(); count+=abs(a-x)+abs(b-y); house.push(pair<int,int>(a,b)); } ans=min(ans,count); } cout<<ans<<endl; return 0; }
package main import ( "fmt" "math" ) func juli(x1, y1, x2, y2 int) int { // 输入两个点的横纵坐标,返回两个点的距离 num_x, num_y := 0, 0 if x1 > x2 { num_x = x1 - x2 } else { num_x = x2 - x1 } if y1 > y2 { num_y = y1 - y2 } else { num_y = y2 - y1 } num := num_x + num_y return num } // 思路 : 在输入 时, 把 0 的横纵坐标 存入一个二维数组, 1 的存入一个二维数组, // 0 的 那个数组挨个取出 横纵坐标, 和 1 的所有横纵坐标 求距离 , 距离相加 func main() { N := 0 _, _ = fmt.Scan(&N) num_list1 := [][]int{} num_list0 := [][]int{} num_1 := 0 // 1的数量 u := 0 for i := 0; i < N; i++ { for j := 0; j < N; j++ { _, _ = fmt.Scan(&u) if u == 1 { num_1 += 1 num_list1 = append(num_list1, []int{i, j}) } else { num_list0 = append(num_list0, []int{i, j}) } } } if num_1 == N*N { fmt.Println(-1) return } sum := 0 min := math.MaxInt64 for i := 0; i < len(num_list0); i++ { for j := 0; j < len(num_list1); j++ { sum += juli(num_list0[i][0], num_list0[i][1], num_list1[j][0], num_list1[j][1]) } if sum < min { min = sum } sum = 0 } fmt.Println(min) }
#include<bits/stdc++.h> using namespace std; int main() { int n = 0; int flag = INT_MAX; int sum = 0; int itmp = INT_MAX; cin >> n; vector<vector<int> > arr(n, vector<int> (n, 0)); vector<pair<int, int> > arr2; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> arr[i][j]; if (0 == arr[i][j]) { flag = 0;//是否能够修建标准位,0不能,1能 arr2.push_back(make_pair(i, j));//记录0的位置 } } } if (0 != flag) { cout << "-1" << endl; return 0; } vector<pair<int, int> >::iterator it = arr2.begin(); while (it != arr2.end()) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (1 == arr[i][j]) { //计算每个0点的修建距离和 sum += (abs(i - (*it).first) + abs(j - (*it).second)); } } } if (sum < itmp) { //得到最小距离和 itmp = sum; } sum = 0; //下一个0点 it++; } cout << itmp << endl; return 0; }
//记录房子坐标点,计算每个空地的距离值,记录最小值 import java.util.ArrayList; import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); while(sc.hasNext()){ int n = sc.nextInt(); int[][] matrix = new int[n][n]; ArrayList<int[][]> al = new ArrayList<>(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { matrix[i][j] = sc.nextInt(); if(matrix[i][j]==1){ int[][] xy = new int[1][2]; xy[0][0]=i; xy[0][1]=j; al.add(xy); } } } int res = Integer.MAX_VALUE; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { int temp=0; if(matrix[i][j]==0){ for (int k = 0; k < al.size(); k++) { temp+=Math.abs(al.get(k)[0][0]-i)+Math.abs(al.get(k)[0][1]-j); } res = res>temp?temp:res; } } } System.out.println(res==Integer.MAX_VALUE?-1:res); } } }
#include<bits/stdc++.h> using namespace std; struct node{ int x,y; }; int main() { int n,sum=0,minn=INT_MAX;cin>>n; vector<node> fang,di; for(int i=0;i<n;i++) for(int j=0;j<n;j++) { int t;cin>>t;node p; p.x=i;p.y=j; if(t) fang.push_back(p); else di.push_back(p); } if(di.empty()) {cout<<-1<<endl;return 0;} for(int i=0;i<di.size();i++) { sum=0; for(int j=0;j<fang.size();j++) sum+=abs(fang[j].x-di[i].x)+abs(fang[j].y-di[i].y); minn=min(minn,sum); } cout<<minn<<endl; }简单易懂。
import java.util.*; public class Main{ public static void main(String[] args){ Scanner in = new Scanner(System.in); int n = in.nextInt(); List<Data> list0 = new ArrayList<>(); List<Data> list1 = new ArrayList<>(); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ int num = in.nextInt(); if(num==0){ list0.add(new Data(i,j)); }else{ list1.add(new Data(i,j)); } } } if(list0.size()==0){ System.out.println(-1); return; } int count=0; int min = Integer.MAX_VALUE; for(int i=0;i<list0.size();i++){ for(int j=0;j<list1.size();j++){ count += (Math.abs(list0.get(i).x-list1.get(j).x) +Math.abs(list0.get(i).y-list1.get(j).y)); } if(count<min){ min = count; } count=0; } System.out.println(min); } static class Data{ public int x,y; public Data(int x,int y){ this.x = x; this.y = y; } } }
n = int(input()) a = [ list(map(int, input().split())) for i in range(n) ] #理想最小 x_sum = 0 y_sum = 0 house_count = 0 for i in range(n): for j in range(n): if a[i][j] == 1: x_sum += i y_sum += j house_count += 1 x_cen = x_sum / house_count y_cen = y_sum / house_count #真实最小:和“理想最小”的diff最小 def real(n, a, x_cen, y_cen): diff = float('inf') diff_tem = 0 x_real = 0 y_real = 0 for i in range(n): for j in range(n): if a[i][j] == 0: diff_tem = abs(i - x_cen) +abs(j-y_cen) if diff_tem < diff: diff = diff_tem x_real = i y_real = j return x_real,y_real if house_count == n * n: print(-1) else: x_real,y_real = real(n, a, x_cen, y_cen) dis = 0 for i in range(n): for j in range(n): if a[i][j] == 1: dis += abs(i-x_real) + abs(j-y_real) print(dis)根据上面大佬们的思路,写了个py3的