今天,我参加了围绕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。如果这足够吃下一件事,我们加上它,吃我们添加的东西,然后吃我们以前不能吃的东西。
如果添加不够,我们不添加它,只删除(忽略)当前的东西)。在这一点上,我可以从循环中断开以跳过所有其他的东西(因为它们都太大而无法进食,列表已经排序了。),但是将它们的数量添加到操作数量以加速我的解决方案,但这不会改变结果。
此代码正确计算样本输入的值,但对于比赛输入不正确。知道为什么吗?
答案 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)
以下是我认为的关键点:
armin, others == 2, [1, 10, 11]
- 删除10
永远不会让11更容易到达我的正确的解决方案实现为:
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的非常好的描述。