如何优化此功能以高效运行?

时间:2015-10-02 20:09:44

标签: c++ algorithm

问题的链接如下:http://codeforces.com/problemset/problem/478/C

你有红色,绿色和蓝色气球。要为宴会装饰一张桌子,你需要三个气球。附在某些桌子上的三个气球不应该有相同的颜色。如果我们知道每种颜色的气球数量,可以装饰哪些表的最大数量?

你的任务是编写一个程序,对于给定的值,r,g和b将找到表的最大数量t,可以按要求的方式进行修饰。

输入: 单行包含三个整数r,g和b(0≤r,g,b≤2·10 ^ 9) - 分别为红色,绿色和蓝色气球的数量。这些数字只相隔一个空格。

输出: 打印单个整数t - 可以按要求的方式装饰的最大表数。

所以,我所做的是,以贪婪的方式,每次都搜索最大值和最小值,如果可能的话,分别减去2和1。这是我的代码:

int main (void)
{
    int ans=0,r,g,b;
    cin>>r>>g>>b;
    while (1)
    {
        int a1 = maxfind(r,g,b);
        int a2 = minfind(r,g,b);
        //ans++;
        if (a1 >= 2 && a2 >= 1)
        {
            ans++;
            if (indma == 1)
                r = r-2;
            else if (indma == 2)
                g = g-2;
            else 
                b = b-2;
            if (indmi == 1)
                r = r-1;
            else if (indmi == 2)
                g = g-1;
            else
                b = b-1;
        }
        else if (r == 1 && g == 1 && b == 1)
        {
            ans++;
            break;
        }
        else
            break;

    }
    cout<<ans<<"\n";

int maxfind(int r, int g, int b)
{
    indma = 0;
    int temp = INT_MIN;
    if (r >= temp)
    {
        temp = r;
        indma = 1;
    }
    if (g >= temp)
    {
        temp = g;
        indma = 2;
    }
    if (b >= temp)
    {
        temp = b;
        indma = 3;
    }
    return temp;
}

类似于findmin的功能,我确保在最大值和最小值相同的情况下选择的数字不同。但是,由于限制是2 * 10 ^ 9,显然,这超过了时间限制。我该如何优化它?谢谢!

编辑:您可以在问题的链接中轻松找到示例测试用例。但是,我还在添加其中一个。

Input
5 4 3
output
4

说明:在第一个样本中,您可以使用以下气球集装饰表:“rgg”,“gbb”,“brr”,“rrg”,其中“r”,“g”和“b”代表红色,绿色和蓝色球分别。

3 个答案:

答案 0 :(得分:4)

您可以将此问题拆分为两种情况,要么使用所有气球(剩下0,1或2),要么不要因为有太多的一种颜色而且不够另外两个。

如果您使用所有气球,答案就是(r + g + b)/ 3

如果你不使用所有的气球,那么答案就等于三个数字中较低的2个的总和。

t = min((r+g+b)/3,r+g+b-max(r,g,b))

答案 1 :(得分:1)

不看问题而只看你的代码:

如果最小数字小于中间数字并且在任何迭代之前至少比最大数字少两个,那么在迭代之后也是如此(因为现在最小数字将小于最大数字,它将比中间数字少两个)。在这种情况下,你可以准确地弄清楚整个算法会发生什么(最大的数字将减少2,直到它不再是最大的,然后两个最大的数字将依次减少两个)。因此,如果没有实际执行所有迭代,您可以确切地确定ans将是什么。

如果两个最小的数字相等且最大值至少为3,则在接下来的两次迭代中,两个最小数字将减少1次,而最大值将减少2次两次。您可以计算发生的频率。

之后你最终得到(x,x + 1,x + 1),(x,x,x + 2),(x,x,x + 1)或(x,x,x)。在这里,您还可以预测下一次迭代或接下来的两次迭代会发生什么。这有点复杂,但不是很复杂。例如,如果三个数字是(x,x,x + 1),那么接下来的三个数字将是(x-1,x,x-1),这又是相同的模式。

示例:以(10 ^ 9,10 ^ 9 + 1,10 ^ 9 + 1000)开始:你将从第一个减去1 500次,从最后一个数减去2,给出(10 ^ 9 - 500,10 ^ 9 + 1,10 ^ 9 + 0)。然后你将10 ^ 9 - 500次将第一个数字减1,并且因为数字是偶数,所以你将其他两个数字中的每一个减少2(10 ^ 9 - 500)/ 2次。此时你有(0,501,500),你的算法以ans = 10 ^ 9结束。

现在这将展示如何在恒定时间内进行计算。它没有显示这是否给出了正确的解决方案。

答案 2 :(得分:1)

  

如何优化此功能以高效运行?

通过更密切地观察问题。蛮力方法不会奏效(不幸的是)。

幸运的是,这些数字可以在一个封闭的等式中计算,而无需借助递归或循环。

让我们尝试推导:你从(r, g, b)气球开始。表的上限肯定是sum(r, g, b) / 3(整数除法,即向下舍入),因为你需要至少三倍于表格的气球。

不是最佳案例怎么样?要装饰一张桌子,你需要两个不同颜色的气球,但你不关心第三个气球的颜色。

假设你有最少的绿色(min(r, b, g) = g)气球。所以你可以装饰g表,只要你有足够的气球(已经覆盖)。你可以装饰多少桌子?

假设您尚未用完所有气球(即g < sum(r, b, g) / 3),您已用完了其他颜色的2 x g气球,即您总共剩下sum(r, b) - 2 x g个气球。这可以是可用的红色和蓝色气球的任意组合,因为我们可以根据需要随意改变它们。

如果我们假设红色(r)气球是次要频率最低的(即大多数气球是蓝色的),我们最多可以装饰min(r, sum(r, b) - 2 x g)个表。我们要么用尽了红色的气球,要么我们的气球用完了,无论哪一个先发生。

由于我们已经涵盖了气球耗尽的情况,我们可以忽略min(r, sum(r, b) - 2 x g)的第二项。

确实,表的数量是min(sum(r, b, g) / 3, min(r + b, r + g, b + g))或简化的min(sum(r, b, g) / 3, sum(r, b, g) - max(r, b, g)),或者通俗地说,是总数的三分之一的最小值和两种最不常用颜色的总和。