这个谷歌代码卡塞练习中我的解决方案有什么不对?

时间:2013-05-04 20:54:25

标签: python algorithm

今天,我参加了围绕1B的谷歌代码堵塞。在代码堵塞中,出现了一个名为“Osmos”的问题:https://code.google.com/codejam/contest/2434486/dashboard

问题描述

问题在于说游戏是一种游戏,玩家只是一种东西,它只能吃比它小的东西,并且会因为他吃的东西而变得更大。例如,如果玩家的大小为10并且吃了大小为8的东西,则它变为大小为18。

现在,考虑到玩家开始的大小,以及游戏中所有其他内容的大小,你应该给出使游戏可以打败所需的最少操作次数,这意味着你最终能够吃一切。

操作可以是添加一些东西,也可以删除一些东西。

我使用的代码

write_case是一个以正确格式为每个测试用例写入输出的函数。我在其他代码卡塞轮中使用它,我知道它是正确的,inp是输入文件的文件对象。

cases = int(inp.readline())
for case in xrange(cases):
    # armin is the variable containing the size of the player,
    armin, n = int(inp.readline.split()[0])
    # others is a list of sizes of other things
    others = [int(x) for x in inp.readline().split()]

    # changes obviously holds the number of required changes
    changes = 0
    for other in sorted(others):  #we loop over all the other things in order.
        if other < armin:  #if the other thing is smaller, eat it, no change needed.
            armin += other
        else: # we'll need to make some changes
            # adding is the biggest size thing the player can eat,
            adding = armin - 1
            if other < armin + adding:  #if adding such a thing is good enough
                                        # to eat the other thing
                armin += adding + other # add it and eat them
                changes += 1 #we've made a change.
            else: # we can't add a big enough thing
                # we have to elete it from the game (skip it from the loop)
                # which is a change 
                changes += 1

    write_case(case + 1, changes ) #output the changes.

我背后的逻辑

通过循环播放从小到大的其他东西,玩家首先吃掉它通常吃的所有东西。当我们遇到一些我们无法吃的东西时,我们吃掉了比它小的东西,所以我们必须添加一个新的东西,这样我们才能成长。如果我们要添加新的东西,我们也可以尽可能地增加它,因为我们添加的东西的大小不会改变操作的数量。我可以添加的最大的食物是玩家的大小-1。如果这足够吃下一件事,我们加上它,吃我们添加的东西,然后吃我们以前不能吃的东西。

如果添加不够,我们不添加它,只删除(忽略)当前的东西)。在这一点上,我可以从循环中断开以跳过所有其他的东西(因为它们都太大而无法进食,列表已经排序了。),但是将它们的数量添加到操作数量以加速我的解决方案,但这不会改变结果。

此代码正确计算样本输入的值,但对于比赛输入不正确。知道为什么吗?

3 个答案:

答案 0 :(得分:2)

我的方法是,每次我找到一个块时,我都会想出需要多少次添加才能继续。然后我建立了添加数量和剩余数量的日志。在我完成设置之后,我反过来循环查看日志以确定添加要继续的节点是否更有效,或者删除每个块点处的剩余节点。现在看看这个,我可以看到一些我可以优化的地方,但我通过下面的C#代码传递了小到大。

protected string Solve(string Line1, string Line2)
{
    string[] Inputs = Line1.Split();
    uint A = uint.Parse(Inputs[0]);
    byte N = byte.Parse(Inputs[1]);
    Inputs = Line2.Split();
    List<uint> Motes = new List<uint>(N);
    foreach (string Size in Inputs)
    {
        Motes.Add(uint.Parse(Size));
    }
    Motes.Sort();
    List<Action> Actions = new List<Action>();

    while (Motes.Count > 0)
    {
        if (A > Motes[0])
        {
            A += Motes[0];
            Motes.RemoveAt(0);
        }
        else if(A > 1)
        {
            uint I;
            for (I = 0; A <= Motes[0]; I++)
            {
                A = (A << 1) - 1;
            }
            Actions.Add(new Action(I, Motes.Count));
        }
        else
        {
            Actions.Add(new Action(101, Motes.Count));
            break;
        }
    }

    uint TotalInserts = 0;
    int TotalRemoved = 0;
    for (int I = Actions.Count - 1; I >= 0; I--)
    {
        int StepRemaining = Actions[I].Remaining - TotalRemoved;
        uint StepInsert = Actions[I].Inserts;
        if (StepInsert >= StepRemaining)
        {
            TotalRemoved += StepRemaining;
            TotalInserts = 0;
        }
        else
        {
            TotalInserts += StepInsert;
            if (TotalInserts >= Actions[I].Remaining)
            {
                TotalRemoved = Actions[I].Remaining;
                TotalInserts = 0;
            }
        }
    }

    return (TotalInserts + TotalRemoved).ToString();
}
struct Action
{
    public uint Inserts;
    public int Remaining;
    public Action(uint inserts, int remaining)
    {
        Inserts = inserts;
        Remaining = remaining;
    }
}

答案 1 :(得分:1)

以下是我认为的关键点:

  1. 永远不希望从列表中心删除。这是一个浪费的操作。考虑armin, others == 2, [1, 10, 11] - 删除10永远不会让11更容易到达
  2. 鉴于此,仅删除列表中的所有剩余项目才有效。因此,如果您必须添加的项目多于列表中剩余的项目以进入下一个元素,那么删除那些大项目会更有效。
  3. 我的正确的解决方案实现为:

    def solve(armin_size, sizes):
        sizes = sorted(sizes)
        steps = 0
    
        for i, size in enumerate(sizes):
            add_count = 0
            remove_count = len(sizes) - i
            while armin_size <= size:
                armin_size += armin_size - 1
                add_count += 1
    
                if add_count >= remove_count:
                    return steps + remove_count
    
            armin_size += size
            steps += add_count
    
        return steps
    

    编辑:刚刚检查了记分牌 - 我弄错了。糟糕。

答案 2 :(得分:1)

所以你的问题看起来如果添加不够好会发生什么......因为你可以在此之后引入另一个微尘来继续喂你的东西,直到它足够大。如果你不打算再给它喂另一个微尘,你也可以说你要删除所有剩余的微尘。

如果您有兴趣,我发表了对此问题here的非常好的描述。