给定 n 个城市和每对城市之间的距离,选择 k 个城市来放置仓库(或 ATM 或云服务器),使得城市到仓库(或 ATM 或云服务器)的最大距离最小。
例如考虑以下四个城市,0、1、2和3以及它们之间的距离,如何在这4个城市之间放置2台ATM,使一个城市到ATM的最大距离最小。
由于该问题是已知的 NP-Hard 问题,因此没有多项式时间解决方案可用于此问题。有一个多项式时间贪心近似算法,贪心算法提供了一个永远不会比最优解更糟的解。只有当城市之间的距离遵循三角不等式(两点之间的距离总是小于通过第三点的距离之和)时,贪婪解决方案才有效。
2-近似贪心算法:
1)任意选择第一个中心。
2) 使用以下标准选择剩余的 k-1 个中心。
让 c1, c2, c3, … ci 是已经选择的中心。选择
(i+1)’th 个中心,选择距离最远的城市
选定的中心,即具有以下值的点 p 为最大值
Min[dist(p, c1), dist(p, c2), dist(p, c3), ….距离(p,ci)]
示例(上图中的 k = 3)
a) 令第一个任意选取的顶点为 0。
b) 下一个顶点是 1,因为 1 是离 0 最远的顶点。
c) 剩下的城市是 2 和 3。计算它们与已经选择的中心(0 和 1)的距离。贪心算法基本上计算以下值。
从 2 到已经考虑的中心的所有距离的最小值
Min[dist(2, 0), dist(2, 1)] = Min[7, 8] = 7
从 3 到已经考虑的中心的所有距离的最小值
Min[dist(3, 0), dist(3, 1)] = Min[6, 5] = 5
计算完上述值后,选择城市2,因为2对应的值最大。
请注意,贪婪算法没有给出 k = 2 的最佳解决方案,因为这只是一个近似算法,其边界是最优值的两倍。
证明上述贪心算法是2近似的。
令 OPT 为最优解中城市与中心的最大距离。我们需要证明从 Greedy 算法得到的最大距离是 2*OPT。
证明可以用矛盾来完成。
a) 假设最远点到所有中心的距离 > 2·OPT。
b) 这意味着所有中心之间的距离也 > 2·OPT。
c) 我们有 k + 1 个点,每对之间的距离 > 2·OPT。
d) 每个点都有一个距离 <= OPT 的最优解的中心。
e) 最优解中存在一对中心X相同的点(鸽巢原理:k个最优中心,k+1个点)
f) 它们之间的距离最多为 2·OPT(三角不等式),这是一个矛盾。
C++
// C++ program for the above approach
#include
using namespace std;
int maxindex(int* dist, int n)
{
int mi = 0;
for (int i = 0; i < n; i++) {
if (dist[i] > dist[mi])
mi = i;
}
return mi;
}
void selectKcities(int n, int weights[4][4], int k)
{
int* dist = new int[n];
vector centers;
for (int i = 0; i < n; i++) {
dist[i] = INT_MAX;
}
// index of city having the
// maximum distance to it's
// closest center
int max = 0;
for (int i = 0; i < k; i++) {
centers.push_back(max);
for (int j = 0; j < n; j++) {
// updating the distance
// of the cities to their
// closest centers
dist[j] = min(dist[j], weights[max][j]);
}
// updating the index of the
// city with the maximum
// distance to it's closest center
max = maxindex(dist, n);
}
// Printing the maximum distance
// of a city to a center
// that is our answer
cout << endl << dist[max] << endl;
// Printing the cities that
// were chosen to be made
// centers
for (int i = 0; i < centers.size(); i++) {
cout << centers[i] << " ";
}
cout << endl;
}
// Driver Code
int main()
{
int n = 4;
int weights[4][4] = { { 0, 4, 8, 5 },
{ 4, 0, 10, 7 },
{ 8, 10, 0, 9 },
{ 5, 7, 9, 0 } };
int k = 2;
// Function Call
selectKcities(n, weights, k);
}
// Contributed by Balu Nagar
Java
// Java program for the above approach
import java.util.*;
class GFG{
static int maxindex(int[] dist, int n)
{
int mi = 0;
for(int i = 0; i < n; i++)
{
if (dist[i] > dist[mi])
mi = i;
}
return mi;
}
static void selectKcities(int n, int weights[][],
int k)
{
int[] dist = new int[n];
ArrayList centers = new ArrayList<>();
for(int i = 0; i < n; i++)
{
dist[i] = Integer.MAX_VALUE;
}
// Index of city having the
// maximum distance to it's
// closest center
int max = 0;
for(int i = 0; i < k; i++)
{
centers.add(max);
for(int j = 0; j < n; j++)
{
// Updating the distance
// of the cities to their
// closest centers
dist[j] = Math.min(dist[j],
weights[max][j]);
}
// Updating the index of the
// city with the maximum
// distance to it's closest center
max = maxindex(dist, n);
}
// Printing the maximum distance
// of a city to a center
// that is our answer
System.out.println(dist[max]);
// Printing the cities that
// were chosen to be made
// centers
for(int i = 0; i < centers.size(); i++)
{
System.out.print(centers.get(i) + " ");
}
System.out.print("\n");
}
// Driver Code
public static void main(String[] args)
{
int n = 4;
int[][] weights = new int[][]{ { 0, 4, 8, 5 },
{ 4, 0, 10, 7 },
{ 8, 10, 0, 9 },
{ 5, 7, 9, 0 } };
int k = 2;
// Function Call
selectKcities(n, weights, k);
}
}
// This code is contributed by nspatilme
Python3
# Python3 program for the above approach
def maxindex(dist, n):
mi = 0
for i in range(n):
if (dist[i] > dist[mi]):
mi = i
return mi
def selectKcities(n, weights, k):
dist = [0]*n
centers = []
for i in range(n):
dist[i] = 10**9
# index of city having the
# maximum distance to it's
# closest center
max = 0
for i in range(k):
centers.append(max)
for j in range(n):
# updating the distance
# of the cities to their
# closest centers
dist[j] = min(dist[j], weights[max][j])
# updating the index of the
# city with the maximum
# distance to it's closest center
max = maxindex(dist, n)
# Printing the maximum distance
# of a city to a center
# that is our answer
# print()
print(dist[max])
# Printing the cities that
# were chosen to be made
# centers
for i in centers:
print(i, end = " ")
# Driver Code
if __name__ == '__main__':
n = 4
weights = [ [ 0, 4, 8, 5 ],
[ 4, 0, 10, 7 ],
[ 8, 10, 0, 9 ],
[ 5, 7, 9, 0 ] ]
k = 2
# Function Call
selectKcities(n, weights, k)
# This code is contributed by mohit kumar 29.
C#
using System;
using System.Collections.Generic;
public class GFG{
static int maxindex(int[] dist, int n)
{
int mi = 0;
for(int i = 0; i < n; i++)
{
if (dist[i] > dist[mi])
mi = i;
}
return mi;
}
static void selectKcities(int n, int[,] weights,
int k)
{
int[] dist = new int[n];
List centers = new List();
for(int i = 0; i < n; i++)
{
dist[i] = Int32.MaxValue;
}
// Index of city having the
// maximum distance to it's
// closest center
int max = 0;
for(int i = 0; i < k; i++)
{
centers.Add(max);
for(int j = 0; j < n; j++)
{
// Updating the distance
// of the cities to their
// closest centers
dist[j] = Math.Min(dist[j],
weights[max,j]);
}
// Updating the index of the
// city with the maximum
// distance to it's closest center
max = maxindex(dist, n);
}
// Printing the maximum distance
// of a city to a center
// that is our answer
Console.WriteLine(dist[max]);
// Printing the cities that
// were chosen to be made
// centers
for(int i = 0; i < centers.Count; i++)
{
Console.Write(centers[i] + " ");
}
Console.Write("\n");
}
// Driver Code
static public void Main (){
int n = 4;
int[,] weights = new int[,]{ { 0, 4, 8, 5 },
{ 4, 0, 10, 7 },
{ 8, 10, 0, 9 },
{ 5, 7, 9, 0 } };
int k = 2;
// Function Call
selectKcities(n, weights, k);
}
}
// This code is contributed by avanitrachhadiya2155.
Javascript
5
0 2
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。