Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 找到最窄区间的算法,其中m将覆盖一组数字_Java_C++_Algorithm_Dynamic Programming_Knapsack Problem - Fatal编程技术网

Java 找到最窄区间的算法,其中m将覆盖一组数字

Java 找到最窄区间的算法,其中m将覆盖一组数字,java,c++,algorithm,dynamic-programming,knapsack-problem,Java,C++,Algorithm,Dynamic Programming,Knapsack Problem,假设您有一个n数字列表。您可以选择m整数(让我们调用整数a)。对于每个整数a,删除包含范围[a-x,a+x]内的每个数字,其中x是一个数字。可以清除列表的x的最小值是多少 例如,如果您的数字列表是 138108205 m=2,答案是x=5 您可以选择两个整数5和20。这将清除列表,因为它会删除[5-5,5+5]和[20-5,20+5]之间的所有数字 我该如何解决这个问题?我认为解决方案可能与动态规划有关。我不想要暴力方法解决方案 代码将非常有用,最好是在java或C++或C. < P>一个有效的

假设您有一个n数字列表。您可以选择m整数(让我们调用整数a)。对于每个整数a,删除包含范围[a-x,a+x]内的每个数字,其中x是一个数字。可以清除列表的x的最小值是多少

例如,如果您的数字列表是

138108205

m=2,答案是x=5

您可以选择两个整数5和20。这将清除列表,因为它会删除[5-5,5+5]和[20-5,20+5]之间的所有数字

我该如何解决这个问题?我认为解决方案可能与动态规划有关。我不想要暴力方法解决方案


代码将非常有用,最好是在java或C++或C.</P> < P>一个有效的算法可以(假设列表排序)->/P>

  • 我们可以把列表看作是一组“m”整数

  • 现在,为每个组计算“最后一个元素-第一个元素+1”,并将该值的最大值存储在一个变量中,比如“ans”

  • 现在,“x”的值是“ans/2”


  • 我希望这个算法的工作原理非常清楚

    我认为这也是类似的集群化问题。例如,您可以使用k-means聚类算法:在m个类上对初始列表进行分区,对于x,将最大大小除以两个获得的类。

    假设你有名单

    1 3 8 10 18 20 25
    
    想知道如果x等于2,需要多少组来覆盖这个集合

    您可以通过贪婪的方式解决这个问题,方法是选择第一个整数为1+x(1是列表中最小的数字)。这将覆盖1+x+x=5的所有元素。然后简单地重复这个过程,直到所有的数字都被覆盖

    在这种情况下,下一个未覆盖的数字是8,所以我们选择8+x=10,覆盖第二组中10+x=12的所有数字

    同样,第三组将涵盖[18,24],第四组将涵盖[25,29]

    这个x值需要4组。这太多了,所以我们需要增加x并重试

    您可以使用二分法来确定x的最小值,该值覆盖m组中的所有数字

    递归解决方案:

    首先,你需要一个估计值,你可以分成m组,然后估计值(x)必须是~(greather-lowerelement)/2*m。估计的(x)可能是一个解决方案。如果有更好的解决方案,它在所有组中的x值都低于extimated(x)!你可以检查第一组,然后递归地重复。问题一直在减少,直到你只有一组:最后一组,你知道你的新解决方案是否更好,如果有更好的,你可以用它来放弃另一个更糟糕的解决方案

    private static int estimate(int[] n, int m, int begin, int end) {
        return (((n[end - 1] - n[begin]) / m) + 1 )/2;
    }
    
    private static int calculate(int[] n, int m, int begin, int end, int estimatedX){
        if (m == 1){
            return estimate(n, 1, begin, end);
        } else {
            int bestX = estimatedX;
            for (int i = begin + 1; i <= end + 1 - m; i++) {
                // It split the problem:
                int firstGroupX = estimate(n, 1, begin, i);
                if (firstGroupX < bestX){
                    bestX = Math.min(bestX, Math.max(firstGroupX, calculate(n, m-1, i, end, bestX)));
                } else {
                    i = end;
                }
            }
            return bestX;
        }
    }
    
    public static void main(String[] args) {
        int[] n = {1, 3, 8, 10, 18, 20, 25};
        int m = 2;
        Arrays.sort(n);
        System.out.println(calculate(n, m, 0, n.length, estimate(n, m, 0, n.length)));
    }
    
    私有静态int估计(int[]n,int m,int begin,int end){
    返回(((n[end-1]-n[begin])/m)+1)/2;
    }
    私有静态int计算(int[]n,int m,int开始,int结束,int估计dx){
    如果(m==1){
    返回估计(n,1,开始,结束);
    }否则{
    int bestX=估计值dx;
    对于(int i=开始+1;i估计){
    long estimatedIsland=估算值(n,1,islandBegin,i+1);
    加上(新长[{estimatedIsland,islandBegin,i,1});
    islandBegin=i+1;
    }
    }
    long estimatedIsland=估算值(n,1,islandBegin,end);
    添加(新长[{estimatedIsland,islandBegin,end,1});
    长期结果;
    if(islands.isEmpty()| | m0){
    long[]island=islands.poll();
    岛[3]++;
    孤岛[0]=解算器(n,孤岛[3],(int)孤岛[1],(int)孤岛[2]);
    岛屿。添加(岛屿);
    姆弗里--;
    }
    结果=islands.poll()[0];
    }
    返回结果;
    }
    公共静态void main(字符串[]args){
    长[]n=新长[63];
    对于(int i=1;i
    1)您应该研究算法的时间和空间复杂性方面的最佳情况、平均情况和最坏情况复杂性

    2) 我认为大卫·佩雷斯·卡布雷拉的想法是正确的。让我们假设平均情况(如下面的伪代码)

    3) 让整数列表用l表示

        keepGoing = true
        min_x = ceiling(l[size-1]-l[0])/(2m)
    
        while(keepGoing)
        {
            l2 = l.copy
            min_x = min_x-1
            mcounter = 1
    
            while(mcounter <= m)
            {
                firstElement = l2[0]
    //  This while condition will likely result in an ArrayOutOfBoundsException
    //  It's easy to fix this.
    
                while(l2[0] <= firstElement+2*min_x)
                {   remove(l2[0])   }
                mcounter = mcounter+1
            }
            if(l2.size>0)
                keepGoing = false
        }
        return min_x+1
    

    到目前为止你试过什么了吗?我对要求有点困惑。m个整数不需要来自列表(例如,示例中的整数5),当您选择它们时,您可以充当对手-试图找到最差的m个整数。因此,x的最小值必须足够大,以处理最坏的情况,无论选择哪个m整数。但既然m整数没有约束,为什么在示例中不选择-50000000000和+50000000000,显著增加所需的x值?或者“对手”有点错误?选择m个整数是否是解决问题的最佳选择?二进制搜索Vx,使用经典贪婪覆盖算法验证guess@BobBilly你能检查一下我的答案吗?我在想清单1、2、3、4、5、6、7。。。100设m=2。这个例子的算法是如何工作的?好的。现在有两组->[1,2,…50]和[51,52,…100],前半部分50-1=49,后半部分100-51=49,它们的最大值=49,所以x=49/2…但我认为我们应该将“ans”增加到“ans”+1,这样ans=25。。或使用“ceil”功能。。现在25-25,25+25,75-25,75+25。。整个列表很清楚。它适用于我给出的示例,但不适用于老师较长的示例(列表中有数千个数字)。它们太长,无法在此处复制/粘贴。你知道为什么有时候这样不行吗?我
        keepGoing = true
        min_x = ceiling(l[size-1]-l[0])/(2m)
    
        while(keepGoing)
        {
            l2 = l.copy
            min_x = min_x-1
            mcounter = 1
    
            while(mcounter <= m)
            {
                firstElement = l2[0]
    //  This while condition will likely result in an ArrayOutOfBoundsException
    //  It's easy to fix this.
    
                while(l2[0] <= firstElement+2*min_x)
                {   remove(l2[0])   }
                mcounter = mcounter+1
            }
            if(l2.size>0)
                keepGoing = false
        }
        return min_x+1
    
    l = {1, 2, 3, 4, 5, 6, 7}, m=2 (gives x=2)
    l = {1, 10, 100, 1000, 10000, 100000, 1000000}, m=2
    l = {1, 10, 100, 1000, 10000, 100000, 1000000}, m=3