0

这是我制作程序的问题

阿里巴巴对四十个小偷做了一个恶作剧,把他们困在一个大山洞里,那里是野狼的家。盗贼没有任何武器,只有盗贼的首领有刀。没有武器他们将无法与狼作战,因此他们决定自杀而不是被活活吃掉。

他们都决定站成一圈,每三个人就自杀,但盗贼首领不喜欢这个想法,也没有自杀的打算。他计算他应该站在哪里,以便他是最后一个离开的人。

HackerMan 想根据这个故事构建一个游戏,但他没有杀死他,而是决定让参与者离开游戏,而不是每个第 3 个位置,而是每个第 2 个位置。当然,这场比赛的参与者人数将远远超过 40 人。

输入

输入的第一行是一个整数 N (1 <= N <= 1000),它指定了测试用例的数量。之后,每一行都包含一个整数 X (5 <= X <= 100000000),它是游戏参与者的数量。

输出

对于每个测试用例,生成一条包含幸存参与者位置的行。假设参与者的序号从 1 到 n,并且从第 1 个人开始计数,即第一个离开的人是第 2 个人。

样本输入

3 5 11 45

样本输出

3 7 27

这是我的解决方案

class SurvivalStrategy {

    public int next;
    public int value;
    public boolean alive;

    SurvivalStrategy(int n, int v)
    {
        this.next = n;
        this.value = v;
        this.alive = true;
    }

    public int getNext(){
        return this.next;
    }
    public void kill(){
        this.alive = false;
    }

    public void changeNext(int n){
        this.next = n;
    }


    public static void main(String[] args) throws IOException {

        System.out.println("Enter the number of cases");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = br.readLine();
        int N = Integer.parseInt(line);
        int[] array = new int[N];
        for(int a = 0; a < N; a++)
        {
            System.out.println("Enter No. of theives in case " + (a + 1));
            array[a] = Integer.parseInt(br.readLine());
        }
        for(int b = 0; b < N; b++)
        {
            try{

                int theives = 0;
                theives = array[b];
                SurvivalStrategy[] people = new SurvivalStrategy[theives];
                int i = 0;
                int nextctr = 2;
                for(i = 0; i < people.length; i++)
                {
                    people[i] = new SurvivalStrategy(nextctr, i + 1);

                    if(nextctr > people.length)
                    {
                        people[i] = new SurvivalStrategy(1, i + 1);
                    }
                    nextctr++;
                }

                int k = 0;
                int nextguy = 0;
                int survivers = people.length;
                boolean CarryOnJatta = true;
                int lastSurviver = 0;
                while(CarryOnJatta)
                {
                    if(k >= people.length)
                    {
                        k = 0;
                        k = k + 2;
                    }
                    if(people[k].alive)
                    {
                        //System.out.println(people[k].value + " is Alive");
                        nextguy = people[k].getNext();
                        if(people[nextguy - 1].alive)
                        {
                            people[nextguy - 1].kill();

                            people[k].changeNext(people[nextguy - 1].next);
                            lastSurviver = people[k].value;
                            survivers--;
                        }else{
                            k = k + 2;
                        }
                        k = k + 2;
                    }else{
                        k = k + 2;
                    }

                    if (survivers == 1)
                    {
                        CarryOnJatta = false;
                        System.out.println("" + lastSurviver);

                    }
                }




            } catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    }
}

我的程序为小值提供输出,但不为大值提供输出。如果我用输入(23987443)尝试它,我会得到java堆大小超出错误。有什么办法可以改善这个程序的空间和时间复杂度。如果它们正在生成所需的输出,我也对其他算法持开放态度。

4

3 回答 3

3

您在堆上分配了至少 23987443 * sizeof(SurvivalStrategy) 内存 - 每个案例大约 300MB,并且仅在这行代码之前:

SurvivalStrategy[] people = new SurvivalStrategy[theives];

我猜这个挑战旨在教你高效内存处理的优点 - 所以不是一次分配整个内存,你需要一个接一个地处理你的项目,这样你一次只分配几个项目,让GC 收集不再需要的那些。

于 2013-02-27T13:17:51.587 回答
0

You could try to assign more memory to the JVM, there's a recent post about this: Java Heap Space error from command line

于 2013-02-27T13:09:22.190 回答
0

您可以使用循环 LinkedList。将您的节点添加到列表中,并使用计数算法遍历列表。每次有人输了,只需对该人调用 remove ,这将标记它有资格进行垃圾收集(假设列表包含您节点的唯一引用)。

更好的是,无需在列表的第一个循环中一次性添加所有人。如果某人是 V 次迭代的倍数,则您可以简单地不添加某人。这应该会大大减少您的内存使用量。

这将节省您的堆空间,因为您保持最大大小为 N,但将有更多的分配/释放开销。尽管如此,linkedList.remove 提供了 O(1) 复杂度。我认为它会清理您的代码并使其更易于理解

于 2013-02-27T17:20:37.083 回答