Algorithm 运行和最大项最小化

Algorithm 运行和最大项最小化,algorithm,computer-science,theory,Algorithm,Computer Science,Theory,我正在制作一个物理优化器,其中一个关键部分由下面的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 ) ); }

我正在制作一个物理优化器,其中一个关键部分由下面的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运行_sum=0;
int sum_峰值=0;
for(int i=0;i<数组的大小;i++)
{
运行_sum+=int_数组[i];
总和峰值=最大值(总和峰值,abs(运行总和));
}
断言(运行_sum==0);
任务是通过排列初始int_数组来最小化结果sum_峰值。到目前为止,我的想法是:这种天真的方法需要指数级的运行时间。我所知道的任何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},使总和峰值为+2。

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

  • 如果int是无符号的,则没有帮助
  • 如有签署,则:
1.输入阵列

  • 1,5,-2,7,-6,4,-10,-3
2.将有符号和无符号的值A分开,并按值排序

  • +1、+4、+5、+7、
  • -2,-3,-6,-10
3.对原始数组重新排序

  • 这可以通过更多的方式来实现
  • 最简单的方法就是偶数+和奇数-
  • +1、-2、+4、-3、+5、-6、+7、-10
  • 这是快速的,但不是最佳的
  • 仍将显著降低峰值
  • 另一个选择是:

    1.while(总和>=0)从+数组中添加数字

    2.while(总和<0)从数组中添加数字

    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; }
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
无效最小值和峰值()
{
常数int N=1000;
int in[N],out[N];
int i、s、sp、e、ip0、im0、ip1、im1;
//生成sum=0随机数组以进行输入和清除(便于调试)

对于(s=0,i=1;i),任务是最小化最大和请澄清这一点。你的意思是对整数重新排序吗?是的。现在应该修复。你需要的解决方案有多好?通过减少到子集和,这个问题是NP完全的,但是一个简单的贪婪算法最多可以获得两倍于最优解的解决方案。要解决一个输入表示为列表
S
,请解决这个问题输入
S+[-sum(S)]
并查看峰值是否为
sum(S)/2
。如果是,则
-sum(S)
将此问题的答案分成两个子集,回答分区问题。否则,分区问题的答案为“否”这并没有给出一个算法来回答这个问题,但我怀疑我们可以找到一个类似的简化方法,将这个问题简化为另一个NP完全问题。