【问题标题】:Running sum maximum item minimization运行总和最大项目最小化
【发布时间】:2014-03-27 01:36:05
【问题描述】:

我正在制作一个物理优化器,其中一个关键部分由以下 CS 问题解决。

给你一个随机有符号整数数组。他们的总和为零。可以创建一个保持运行总和的循环,如下所示:

int running_sum = 0;
int sum_peak = 0;

for( int i = 0; i < size_of_array; i++ )
{
  running_sum += int_array[i];
  sum_peak = max( sum_peak, abs( running_sum ) );
}

assert( running_sum == 0 );

任务是通过置换初始 int_array 来最小化结果 sum_peak。到目前为止,我的想法是:天真的方法需要指数级的时间来运行。我所知道的任何 NP-C 问题似乎都没有表达这个问题。我想不出任何方法可以将此问题表示为图形问题。

如果 X 是数组中的最大数(按绝对值),则 max_sum 的上限和下限分别为 N 和 N/2。

编辑:示例。

{-4, -6, 10}:将列表重新排序如下:{-6, 10, -4},因此 sum_peak 为 -6。

{1, 1, 1, 1, -4}:将列表重新排序为:{ 1, 1, -4, 1, 1 },使得 sum_peak 为 +2。

【问题讨论】:

  • "任务是最小化 max_sum。"请澄清这一点。
  • 你的意思是重新排序整数吗?
  • 是的。现在应该修好了。
  • 您需要的解决方案有多好?这个问题通过归约到子集和是 NP 完全的,但是一个简单的贪心算法最多可以得到一个最优解的两倍。
  • 要解决partition problem 的输入表示为列表S,请使用输入S+[-sum(S)] 解决此问题,并查看峰值是否为sum(S)/2。如果是,-sum(S) 将这个问题的答案分成两个子集来回答分区问题。否则,分区问题的答案是“否”。这并没有给出一个算法来回答 this 问题,但我怀疑我们可以找到从这个问题到另一个 NP 完全问题的类似简单的简化。

标签: algorithm computer-science theory


【解决方案1】:

这可能是假的(如果我误解了问题)但有时最简单的方法是最好的方法

  • 如果 int 是无符号的,则没有帮助
  • 如果有签名则:

1.输入数组

  • 1,5,-2,7,-6,4,-10,-3,...

2.分离有符号和无符号值并按值排序

  • +1,+4,+5,+7,...
  • -2,-3,-6,-10,...

3.重新排序原始数组

  • 这可以通过更多方式完成
  • 最简单的就是偶数是+,奇数是-
  • +1,-2,+4,-3,+5,-6,+7,-10
  • 这很快,但不是最佳的
  • 仍然会显着降低峰值
  • 另一种选择是:

    1.while (sum>=0) 从 +array 中添加数字

    2.while (sum

    3.当一个数组全部使用时,复制未使用的其余部分

  • 不要认为你可以做得比这更好

NP 完整从何而来???

  • 或者我错过了什么???

[编辑 1]

  • 也可以改进以获得最佳解决方案,如
  • 使用较大的未使用值中的较小值来获得对面数组中最大未使用值的一半...
  • 也都可以就地完成

[编辑 2] 一些代码和测试

//---------------------------------------------------------------------------
void min_sum_peak()
    {
    const int N=1000;
    int in[N],out[N];
    int i,s,sp,e,ip0,im0,ip1,im1;
    // generate sum=0 random array to in and clear out (for easyier debug)
    for (s=0,i=1;i<N;i++)
        {
        in[i]=Random(1000)-500;
        s+=in[i];
        out[i]=0;
        } in[0]=-s; out[0]=0;

    // bubble sort in[]
    for (e=1;e;)
    for (e=0,i=1;i<N;i++)
     if (in[i-1]>in[i])
      { e=in[i-1]; in[i-1]=in[i]; in[i]=e; e=1; }


    // fill out[]
    #define peak { e=s; if (e<0) e=-e; if (sp<e) sp=e; }
    for (int mode=0;mode<3;mode++)
        {
        // scann for +/- boundary
        im0=-1; ip0=N;
        im1= 0; ip1=N-1;
        for (i=0;i<N;i++)
         if (in[i]<0) im0=i;
          else { ip0=i; break; }

        if (mode==0)            // even odd from smaller values (sp = ~2*max)
         for (i=0,s=0,sp=0;i<N;)
            {
            if (im0>=im1){ out[i]=in[im0]; s+=out[i]; im0--; i++; peak; }
            if (ip0<=ip1){ out[i]=in[ip0]; s+=out[i]; ip0++; i++; peak; }
            }
        if (mode==1)            // even odd from bigger values (sp = ~max)
         for (i=0,s=0,sp=0;i<N;)
            {
            if (im0>=im1){ out[i]=in[im1]; s+=out[i]; im1++; i++; peak; }
            if (ip0<=ip1){ out[i]=in[ip1]; s+=out[i]; ip1--; i++; peak; }
            }
        if (mode==2)            // -half sum to next max value (sp = ~0.5*max for big enough array)
            {
            for (i=0,s=0,sp=0;;)
                {
                if (im0<im1) break; // stop if any + or - valueas are exhausted
                if (ip0>ip1) break;
                if (s>=0)
                    {
                    if (+s+s<-in[im1]){ out[i]=in[ip0]; s+=out[i]; ip0++; i++; }
                    else              { out[i]=in[im1]; s+=out[i]; im1++; i++; }
                    }
                else{
                    if (-s-s<+in[ip1]){ out[i]=in[im0]; s+=out[i]; im0--; i++; }
                    else              { out[i]=in[ip1]; s+=out[i]; ip1--; i++; }
                    }
                peak;
                }
            for (;im0>=im1;){ out[i]=in[im0]; s+=out[i]; im0--; i++; peak; }
            for (;ip0<=ip1;){ out[i]=in[ip0]; s+=out[i]; ip0++; i++; peak; }
            }
        i=-in[0]; if (i<in[N-1]) i=in[N-1];
        // breakpoint here for approach assesment
        mode=mode;  // used approach
        i = i;      // abs max value
        s = s;      // sum
        sp=sp;      // sum peak
        }
    #undef peak { e=s; if (e<0) e=-e; if (sp<e) sp=e; }
    }
//---------------------------------------------------------------------------
  • 模式 0 - 较小值的偶奇数 sp = ~2*max_abs_value
  • 模式 1 - 较大值的偶奇数 sp = ~max_abs_value
  • 模式 2 - 一半和到下一个最大值 sp = ~0.5*max_abs_value
  • 对于具有“均匀”分布 +/- 值的足够大的数组,模式 2 符合预期
  • 但如果数组很小(例如 N=20),则模式 1 是赢家
  • mode 0 一点都不好

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多