与兔子一起运行的 Google Foobar Level 4 堆栈溢出

Posted

技术标签:

【中文标题】与兔子一起运行的 Google Foobar Level 4 堆栈溢出【英文标题】:Google Foobar Level 4 RunningWithTheBunnies *** 【发布时间】:2017-12-04 08:42:17 【问题描述】:

我正面临未知输入的 *** 异常。我在本地尝试了许多测试用例,但找不到一个。但是在提交我的解决方案时,我遇到了它。有人可以指出我缺少的测试用例或建议更好的方法吗?

问题和我的代码如下

你和你获救的兔子囚犯需要摆脱这个空间站崩溃的死亡陷阱——而且要快!不幸的是,一些兔子因长期监禁而变得虚弱,不能跑得很快。他们的朋友正在努力帮助他们,但如果你也投入其中,这次逃跑会更快。防御舱壁门已经开始关闭,如果你不及时通过,你会被困住!您需要尽可能多地抓住兔子并在它们关闭之前通过舱壁。

从起点移动到所有兔子和隔板所需的时间将以整数方阵的形式提供给您。每一行都会告诉您到达起点所需的时间,第一只兔子,第二只兔子,...,最后一只兔子,以及按顺序排列的隔板。行的顺序遵循相同的模式(开始,每个兔子,隔板)。兔子可以跳进你的怀抱,因此可以立即将它们捡起来,并且在密封的同时到达舱壁仍然可以成功逃脱,即使是戏剧性的逃脱。 (别担心,任何你没有捡起的兔子都可以和你一起逃跑,因为它们不再需要携带你捡到的兔子。)如果你愿意,你可以重新访问不同的地方,然后移动到舱壁并不意味着您必须立即离开——如果时间允许,您可以往返于舱壁以捡起更多的兔子。

除了花时间在兔子之间穿梭外,一些路径还与空间站的安全检查站互动,并将时间倒回时钟。向时钟添加时间将延迟舱壁门的关闭,如果在门已经关闭后时间回到 0 或正数,则会触发舱壁重新打开。因此,也许可以绕着圈走并不断获得时间:也就是说,每次经过一条路径,都会使用或增加相同的时间。

编写一个形式为 answer(times, time_limit) 的函数来计算您可以捡起的兔子数量以及它们是哪些兔子,同时在门永远关闭之前仍然通过舱壁逃生。如果有多组相同大小的兔子,则按排序顺序返回具有最低囚犯 ID(作为索引)的兔子组。 兔子按囚犯ID表示为一个排序列表,第一个兔子为0。兔子最多有5个,time_limit是一个非负整数,最多为999。

For instance, in the case of  
[  
    [0, 2, 2, 2, -1],  # 0 = Start  
    [9, 0, 2, 2, -1],  # 1 = Bunny 0  
    [9, 3, 0, 2, -1],  # 2 = Bunny 1  
    [9, 3, 2, 0, -1],  # 3 = Bunny 2  
    [9, 3, 2, 2,  0],  # 4 = Bulkhead  
]  

时间限制为 1,内五行分别指定起点、bunny 0、bunny 1、bunny 2、舱壁门出口。你可以走这条路:

Start End Delta Time Status
    -   0     -    1 Bulkhead initially open
    0   4    -1    2
    4   2     2    0
    2   4    -1    1
    4   3     2   -1 Bulkhead closes
    3   4    -1    0 Bulkhead reopens; you and the bunnies exit

使用这个解决方案,你会捡起兔子 1 和 2。这是这个空间站走廊的最佳组合,所以答案是 [1, 2]。

测试用例

输入:

(int) times = [[0, 1, 1, 1, 1], [1, 0, 1, 1, 1], [1, 1, 0, 1, 1], [1, 1, 1, 0, 1], [1, 1, 1, 1, 0]]  
(int) time_limit = 3  

输出:

(int list) [0, 1]  

输入:

(int) times = [[0, 2, 2, 2, -1], [9, 0, 2, 2, -1], [9, 3, 0, 2, -1], [9, 3, 2, 0, -1], [9, 3, 2, 2, 0]]  
(int) time_limit = 1  

输出:

(int list) [1, 2]  

我的代码 我基本上做的是我首先检查是否存在负循环。如果是,那么所有的兔子都可以被救出。如果没有,那么我基本上会做一个 dfs。

import java.io.*;
import java.util.*;


public class RunningWithTheBunnies

    public static int maxCount = 0;
    public static int[] toReturn = null;
    public static int[] arr = new int[5];
    public static int rows = 0;
    public static void main(String[] args) throws IOException
    
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int rows = Integer.parseInt(br.readLine());
        int[][] times = new int[rows][rows];
        String[] arr = null;
        for(int i = 0 ; i < rows ; i++)
        
            arr = br.readLine().split(" ");
            for(int j = 0 ; j < rows ; j++)
            
                times[i][j] = Integer.parseInt(arr[j]);
            
        
        int time_limit = Integer.parseInt(br.readLine());
        System.out.println(answer(times,time_limit));
        for(int i = 0 ; i < toReturn.length ; i++)
        
            System.out.print(toReturn[i] + " ");
        
        System.out.println("");
    


    public static int[] answer(int[][] times,int time_limit)
    
        rows = times.length;
        int containsCycle = containsNegativeCycle(times);
        if(containsCycle == 1)
            System.out.println("has negative cycle");// for degubbing
            toReturn = new int[rows - 2];
            for(int i = 0 ; i < rows - 2 ; i++)
            
                toReturn[i] = i;
            
            return toReturn;
        
        else
        
            System.out.println("has no negative cycle");// for debugging
            //return new int[2];
            int[] visiting = new int[rows];
            for(int i = 0 ; i < rows ; i++)
            
                visiting[i] = -2;
            
            dfs(0,0,time_limit,visiting,times);
            return toReturn;
        
    

public static void dfs(int vertex,int count,int timeStatus,int[] visiting,int[][] times)

    if(timeStatus < -1)
        return;
    System.out.println("at vertex : " + vertex + ", with status = " + timeStatus);// for debugging purpose.

    visiting[vertex] = timeStatus;
    for(int i = 0 ; i < rows ; i++)
    
        if(i != vertex && visiting[i] == -2 && timeStatus - times[vertex][i] > -2)
        
            //arr[count] = i;
            //dfs(vertex,count + 1,timeStatus - times[vertex][i],visiting,times);
            if(i != 0 && i != rows - 1)
            
                arr[count] = i - 1;
                dfs(i,count + 1,timeStatus - times[vertex][i],visiting,times);
            
            else
            
                dfs(i,count,timeStatus - times[vertex][i],visiting,times);
            
        
        // else if(i != vertex && (visiting[i] < timeStatus - times[vertex][i] || i == rows - 1 || i == 0) && timeStatus - times[vertex][i] > -2)
         else if(i != vertex && timeStatus - times[vertex][i] > -2)
        
            dfs(i,count,timeStatus - times[vertex][i],visiting,times);
        
    
     if(vertex == rows - 1 && timeStatus >= 0 && arr.length > maxCount)
    
        toReturn = new int[arr.length];
        for(int i = 0 ; i < arr.length ; i++)
        
            toReturn[i] = arr[i];
            System.out.println("added " + toReturn[i] + ",at i = " + i );// for debugging
        
        maxCount = arr.length;
    

    visiting[vertex] = -2;


    public static int containsNegativeCycle(int[][] times)
    
        int[] dist = new int[rows];
        dist[0] = 0;
        for(int i = 1 ; i < rows ; i++)
        
            dist[i] = Integer.MAX_VALUE;
        

        for(int k = 0 ; k < rows - 1 ; k++)
        
            for(int i = 0 ; i < rows ; i++)
            
                for(int j = 0 ; j < rows ; j++)
                
                    if(i != j && dist[i] != Integer.MAX_VALUE)
                    
                        if(dist[j] > dist[i] + times[i][j])
                        
                            dist[j] = dist[i] + times[i][j];
                        
                    
                
            
        

        for(int i = 0 ; i < rows ; i++)
        
            for(int j = 0 ; j < rows ; j++)
            
                if(i != j && dist[j] > dist[i] + times[i][j])
                    return 1;
            
        
        return 0;
    

【问题讨论】:

过多的格式使您看起来像是用蜡笔写了整篇文章。请谨慎使用标记并将其用于预期目的。 *** 的问题是因为嵌套递归调用的数量很大(A 调用 B 调用 C ....),它会吃掉所有的内存,从而产生错误。一种测试方法是您需要创建一个大型测试用例并将堆栈内存设置为适当的大小(类似于真实环境)。解决此问题的一种方法是将递归方法更改为迭代方法。 【参考方案1】:

您正在使用Floyd–Warshall algorithm 检查图形是否包含负循环,但您不仅应该检查,而且应该删除它们(!)。使用简化图,您的路径中没有循环,并且最大可能路径包含 5 个兔子 + 入口 + 出口,因此总共 7 个元素没有任何堆栈溢出。

如果顶点上有负循环,您应该先检查它们,如果存在则返回所有兔子。如果某个顶点存在负循环,则意味着您拥有无限的时间资源,因此您可以收集每只兔子而无需担心时间。

执行步骤如下:

    减少负循环图。 检查顶点的负循环。 生成所有可能的路径(对于最多 5 只兔子,蛮力是可以接受的)。 按正确顺序选择最佳路径。

【讨论】:

以上是关于与兔子一起运行的 Google Foobar Level 4 堆栈溢出的主要内容,如果未能解决你的问题,请参考以下文章

Google Foobar 世界末日燃料挑战指数错误

题解拯救花园

python 在Google的Foobar挑战中尝试练习级别3.1“查找访问代码”失败。

python 在Google的Foobar挑战中尝试练习级别3.1“查找访问代码”失败。

Google Foobar 测试用例失败

Google Foobar Challenge,一个测试用例失败