我怎样才能优化它以一种有效的方式运行

How can I optimise this to run in an efficient manner?

本文关键字:一种 有效 运行 方式 优化      更新时间:2023-10-16

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

你有r个红色,g个绿色和b个蓝色的气球。要装饰宴会上的一张桌子,你正好需要三个气球。桌子上的三个气球颜色不应该相同。如果我们知道每种颜色气球的数量,最多可以装饰多少张桌子?

你的任务是编写一个程序,对于给定的值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"answers"b"分别代表红色,绿色和蓝色的球。

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

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

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

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

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

如果在任何迭代之前最小的数小于中间的数,并且至少比最大的数小2,那么在迭代之后也是如此(因为最小的数现在将小于最大的数,并且它将比中间的数小2)。在这种情况下,你可以弄清楚在你的算法中会发生什么(最大的数字会减少2,直到它不再是最大的,然后两个最大的数字会依次减少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)开始:你将500次从第一个数字减去1,从最后一个数字减去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结束。

现在这展示了如何在常数时间内进行计算。它没有显示这是否给出了正确的解。

我如何优化它以有效的方式运行?

通过更仔细地观察这个问题。很不幸,暴力破解方法是行不通的。

幸运的是,这些数字可以在一个封闭方程中计算出来,而不需要递归或循环。

让我们尝试一个推导:你从(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)),或者,通俗地说,是总数的三分之一的最小值和两种最不常见的颜色的总和。

相关文章: