📜  K中心问题|集合1(贪心近似算法)

📅  最后修改于: 2021-04-24 21:29:14             🧑  作者: Mango

给定n个城市以及每对城市之间的距离,请选择k个城市来放置仓库(或ATM或Cloud Server),以使城市到仓库(或ATM或Cloud Server)的最大距离最小。

例如,考虑以下四个城市,分别为0、1、2和3,以及它们之间的距离,如何在这四个城市中放置2个ATM,以使城市到ATM的最大距离最小。

kcenters1

没有可用于该问题的多项式时间解,因为该问题是已知的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),…。 dist(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为城市到市中心的最大距离。我们需要证明,从贪婪算法获得的最大距离是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.


输出
5
0 2