【问题标题】:Optimizing C code [closed]优化 C 代码 [关闭]
【发布时间】:2013-01-14 15:47:37
【问题描述】:

假设我们有一个数字数组,例如 {1,2,3},我们希望在尽可能少的圈数内使数字相等;其中“转弯”的定义如下:

您需要将其中一个元素的值按原样固定,然后每隔一个数字加 1。

考虑到例如。已经提到 - A={1,2,3} ,目标是使它们均衡。我已经做的是制定逻辑,即使用最小圈数的方法是在每圈中选择最大圈数。

迭代 1:保持 A[2]=3。迭代结束时的数组 => {2,3,3}

迭代 2:保持 A[2]=3。迭代结束时的数组 => {3,4,3}

迭代 3:保持 A[1]=4。迭代结束时的数组 => {4,4,4}

所以,转数 = 3

我写的代码如下:

#include<iostream>
#include<stdio.h>

int findMax(int *a,int n)
{
    int i,max;
    max=1;
    for(i=2;i<=n;i++)
    {
        if(a[i]>a[max])
        {
            max=i;
        }     

    }
    return max;
}

int equality(int *a,int n)
{
    int i;
    for(i=1;i<n;i++)
    {
        if(a[i]!=a[i+1]) return 0;
    }
    return 1;
}

int main()
{
    int a[100],i,count,t,posn_max,n,ip=0;
    scanf("%d",&t);
    while(ip<t)
    {
        count=0;
        scanf("%d",&n);

        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        while(equality(a,n)==0)
        {
            posn_max=findMax(a,n);

            for(i=1;i<=n;i++)
            {
                if(i!=posn_max)
                {
                    a[i]=a[i]+1;
                }
            }
            count++;

        }
        printf("%d\n",count);
        ip++;
    }
    return 0;
}

这给了我我需要的正确答案。但我想进一步优化它。

我的时间限制是 1.0 秒。但是法官网站告诉我我的代码需要 1.01 秒。谁能帮帮我?

据我所知,与 cout/cin 相比,我使用了 scanf/printf 语句,以优化输入/输出部分。但是我还应该做得更好吗?

【问题讨论】:

  • printf 不是很快...我怀疑它比cout 快。
  • 同样存在缓冲区溢出。在循环的最后运行 i = n-1,所以 a[i + 1] 是 a[n],它是 n 长度数组 a 的第 n+1 个元素。
  • 您似乎认为数组从索引 1 开始。它们实际上从 0 开始。
  • 你可能会使用这样一个事实,即初始最大元素将始终是最大值,除非它在上次迭代中没有增加
  • 我想我会先对数组进行排序(可能按降序排列)。然后,您只需遍历阵列即可完成其余的工作。现在你的算法是 O(N^2)。排序将是 O(N log N)。

标签: c++ c algorithm optimization


【解决方案1】:

在您的算法中,您将期望中的所有数字都增加为最大值。

如果你反过来做,减少最大值并保留其余数字,结果应该是相同的(但内存/数组操作要少得多)!

为了让它更快,你可以完全摆脱内存操作(正如Ivaylo Strandjev 所建议的那样):找到最小数字,通过上面的想法(减少数字而不是增加)你知道减少了多少您需要将所有数字减少到这个最小数字。因此,在找到最小值后,您需要一个循环来计算圈数。

{1,2,3}为例

  • 最小值为 1
  • 圈数:(1-1)+(2-1)+(3-1) = 0 + 1 + 2 = 3

如果你真的很聪明,可以在输入数字时直接计算圈数并跟踪当前的最小圈数……试试吧! ;)

【讨论】:

  • 仍然有效:(0-0)+(2-0)+(3-0)=5 转。原始算法:{1,3,3},{2,4,3}, {3,4,4}, {4,5,4}, {5,5,5}=5 转
【解决方案2】:

您只关心计数,而不关心您需要执行的实际操作。因此,与其逐个执行动作,不如尝试找到一种方法来计算执行动作的次数。你写的代码再优化也不会超过时限。您所做的最大元素观察将在此过程中为您提供帮助。

【讨论】:

    【解决方案3】:

    除了其他 cmets,如果我做对了并且您的代码有点太慢,这里有两个优化应该可以帮助您。

    首先,您可以将equality() 和findMax() 结合起来,只扫描一次数组,而不是当前最坏的情况(两次)。

    其次,您可以将“增加”循环分成两部分(低于和高于最大位置)。这将消除检查循环中位置的工作。

    【讨论】:

      【解决方案4】:

      1) 尝试展开循环 2)你可以使用SIMD指令吗?这真的会加快这段代码的速度

      【讨论】:

        【解决方案5】:

        我会在一个单独的线程中printf,因为它是一个 I/O 操作并且比您的计算慢得多。

        它也不需要复杂的管理,例如生产者-消费者队列,因为你只传递从 0 到最后一个的有序数字count

        伪代码如下:

            volatile int m_count = 0;
            volatile bool isExit = false;
        
            void ParallelPrint()
            {
                int currCount = 0;
        
                while (!isExit)
                {
                    while (currCount < m_count)
                    {
                        currCount++;
                        printf("%d\n", currCount);
                    }
        
                    Sleep(0); // just content switch
                }
            }
        

        scanf("%d",&amp;t);之前打开线程(我估计这个初始化时间不算),在你的Main()返回之前关闭isExit = true;之前的线程。

        【讨论】:

          猜你喜欢
          • 2011-11-24
          • 1970-01-01
          • 1970-01-01
          • 2011-11-02
          • 2011-11-03
          • 2017-02-18
          • 1970-01-01
          • 1970-01-01
          • 2011-01-24
          相关资源
          最近更新 更多