【问题标题】:Optimizing and finding the computation of this inequality优化并找到这个不等式的计算
【发布时间】:2014-03-22 16:13:24
【问题描述】:

假设我有一组整数,我想从中找出满足特定不等式的所有最大整数数。为了解释,

r1, r2, r3, ... rn 当 r i 是一个正整数。我希望找到从 1 到 n 的最大 z,其中 ri1 + r2 + r3 + ... + rn) 表示 all i 从 3 到 z。如何处理此类问题?我有一种简单的方法,即找到从 1 到 n 的所有大小子集并遍历每个子集以检查每个元素是否满足条件?还有其他方法吗?

【问题讨论】:

  • 值可以是负数吗?
  • @OliCharlesworth 除非我算错了,如果rn > 0 代表所有n,那么任何z >= 2 都会满足条件,所以最大z 将是n跨度>
  • 否 @ThoAppelsin ,如果 {1,2,3} 不适用于任何大于 3 的此类子集,则等式不成立。
  • @ThoAppelsin:考虑 r = { 8, 1, 1 }。 z=n 不是这里的情况 (r1 > 0.5*(8+1+1))。
  • 好吧,如果没有z 满足条件,您希望得到的答案是什么?有没有像r_n 这样的条件是一个递增的集合?

标签: java c algorithm


【解决方案1】:

我感觉有点糟糕,尤其是我对问题所做的错误编辑......无论如何:

首先,解决这个问题的最天真、最直接、最直接的方法;这将从集合中的第一个数字开始,计算每一步的nth 部分总和,将该部分总和与从第三个元素开始的每个元素的双精度进行比较,直到 nth 元素.如果比较对每个元素都成立,则将当前最后一个标记为最大值z

下面的宏 largestzfinder,依赖于函数 largestzfinderfunc 这样做:

// indices are zero based

#define largestzfinder(_x_) largestzfinderfunc((_x_), sizeof(_x_) / sizeof(*_x_))

unsigned int largestzfinderfunc( unsigned int set[], size_t size ) {

    unsigned int largestz = 0;
    unsigned int partialsumsofar = 0;
    int disqualified;

    for ( int i = 0; i < size; i++ ){
        partialsumsofar += set[i];

        disqualified = 0;
        for ( int j = 2; j <= i; j++ ) {    // for all j from 2 to i (inclusive)
            if ( 2 * set[j] > partialsumsofar ) {
                disqualified = 1;
                break;
            }
        }

        if ( !disqualified )    // if comparison held for all j
            largestz = i;
    }

    return largestz;
}

使用这种方法,我们从 最小的 z 开始逐渐到达我们的largestz,然后找到下一个更大的 z,直到我们到达 最大。我们可以从头开始简化该过程,在这种情况下,除了 最大的 之外,我们不必遍历所有其他 zs,并且我们不需要其他的要么……

为此,我们需要预先计算整个和,然后从最后一个元素开始逐个减少,以同样的方式与缩小的部分和进行比较,并在找到后立即返回答案非disqualified 候选人。下面的代码就是这样做的:

// indices are zero based

#define largestzfinder(_x_) largestzfinderfunc((_x_), sizeof(_x_) / sizeof(*_x_))

unsigned int largestzfinderfunc( unsigned int set[], size_t size ) {

    unsigned int largestz = 0;
    unsigned int partialsumsofar = 0;
    int disqualified;

    for ( int i = 0; i < size; i++ )
        partialsumsofar += set[i];

    for ( int i = size - 1; i >= 0; i-- ){

        disqualified = 0;
        for ( int j = 2; j <= i; j++ ) {    // for all j from 2 to i (inclusive)
            if ( 2 * set[j] > partialsumsofar ) {
                disqualified = 1;
                break;
            }
        }

        if ( !disqualified ) {  // if comparison held for all j
            largestz = i;
            break;
        }

        partialsumsofar -= set[i];  // updates/reduces partialsumsofar
    }

    return largestz;
}

现在,您看,我们检查条件是否适用于从第 3 个到最后一个的每个元素,一个接一个...而我们可以只检查其中最大的一个!如果largestamongthem &lt;= partialsumsofar / 2,那么它们都将小于或等于到目前为止的部分总和。

您将如何确定largestsofar?好吧,事情变得复杂了,尤其是当您从头开始执行该过程时。如果我们从一开始就这样做,那么我们可以从 largestsofar = 0; 开始,然后将每个后续元素与它进行比较,更新我们的 largestsofar

一种方法是创建一个与集合数组具有相同大小的新整数数组,它将为每个点保存largestsofar。以下代码使用该方法:

// indices are zero based

#define largestzfinder(_x_) largestzfinderfunc((_x_), sizeof(_x_) / sizeof(*_x_))

unsigned int largestzfinderfunc( unsigned int set[], size_t size ) {

    unsigned int largestz = 0;
    unsigned int partialsumsofar = 0;
    unsigned int * largestsofar = calloc( size, sizeof * largestsofar );

    for ( int i = 0; i < size; i++ )
        partialsumsofar += set[i];

    largestsofar[0] = 0;
    largestsofar[1] = 0;
    largestsofar[2] = set[2];
    for ( int i = 3; i < size; i++ )
        largestsofar[i] = (set[i] > largestsofar[i-1]) ? set[i] : largestsofar[i-1];

    for ( int i = size - 1; i >= 0; i-- ){

        if ( 2 * largestsofar[i] <= partialsumsofar ) {
            largestz = i;
            break;
        }

        partialsumsofar -= set[i];
    }

    free( largestsofar );

    return largestz;
}

好吧,如果您对分配内存不满意,请在其中保留迄今为止最大数字的列表,我支持您。下面的递归函数做的事情,没有保留一个列表。它看起来也短得多。缺点是它对读者不太友好。这里:

// indices are zero based

#define largestzfinder(_x_) largestzfinderfunc((_x_), sizeof(_x_) / sizeof(*_x_), (_x_)[0] + (_x_)[1], 1, 0)

unsigned int largestzfinderfunc( unsigned int set[], size_t size, unsigned int partialsumsofar, unsigned int i, unsigned int largestsofar ){
    unsigned int j;
    if ( i < size - 1 && ( j = largestzfinderfunc( set, size, partialsumsofar + set[i + 1], i + 1, ( set[i + 1] > largestsofar ) ? set[i + 1] : largestsofar ) ) ){
        return j;
    }
    else if ( 2 * largestsofar <= partialsumsofar ) {
        return i;
    }
    else
        return 0;
}

让我简要解释一下它的作用:通过调用宏,它首先将r_0 + r_1 作为partialsumsofar1 作为要检查的当前z,并将0 作为最大的数字,直到r_1(这是因为在比较时不考虑r_0r_1)。

但是,它不会立即检查;如果这不是最后一个元素 (i &lt; size - 1),它将调用该函数一层,更新partialsumsofar,当前 z 被检查递增,最大数字也被更新。这将一直持续到到达最后一个元素。

之后,递归树将崩溃。如果最后一个不满足条件,它会返回一个0,导致父递归分支检查他/她是否满足条件。

只要一个父节点满足条件,它就会返回它当前的 z,导致每个父节点都返回相同的 z,因为它们都将返回的值存储在 j 下并返回它,如果 j 不为零.

本质上,它确实为每个largestsumsofarpartialsumsofar 分配内存,但是当递归树/行/任何东西崩溃时,它会一一释放所有这些。

这不是那么简短,但无论如何,我希望这次我做对了。我现在想解决这个问题...

【讨论】:

    猜你喜欢
    • 2021-02-25
    • 2013-01-15
    • 2013-05-13
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多