【问题标题】:UCF HSPT 2016 - Chomp ChompUCF HSPT 2016 - 咬咬
【发布时间】:2016-03-10 15:00:15
【问题描述】:

在 UCF HSPT 编程竞赛中,我很难找到问题 #9 的有效解决方案。整个pdf我们可以查看here,问题被称为“Chomp Chomp!”。

本质上,问题涉及从数组中取出 2 个“chomp”,其中每个 chomp 是数组中元素的连续链,并且 2 个 chomp 之间必须至少有未“chomped”的元素。一旦确定了两个“chomps”,两个“chomps”中所有元素的总和必须是输入中给定数字的倍数。我的解决方案本质上是一种蛮力,它会遍历所有可能的“chomp”,我试图通过存储先前计算的 chomp 总和来提高它的速度。

我的代码:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

public class chomp {
    static long[] arr;

    public static long sum(int start, int end) {
        long ret = 0;
        for(int i = start; i < end; i++) {
            ret+=arr[i];
        }
        return ret;
    }

    public static int sumArray(int[] arr) {
        int sum = 0;
        for(int i = 0; i < arr.length; i++) {
            sum+=arr[i];
        }
        return sum;
    }

    public static long numChomps(long[] arr, long divide) {
        HashMap<String, Long> map = new HashMap<>();
        int k = 1;
        long numchomps = 0;
        while(true) {
            if (k > arr.length-2) break;
            for (int i = 0; i < arr.length -2; i++) {
                if ((i+k)>arr.length-2) break;
                String one = i + "";
                String two = (i+k) + "";
                String key1 = one + " " + two;
                long first = 0;
                if(map.containsKey(key1)) {
                    //System.out.println("Key 1 found!");
                    first = map.get(key1).longValue();
                } else {
                    first = sum(i, i+k);
                    map.put(key1, new Long(first));
                }
                int kk = 1;
                while(true){
                    if (kk > arr.length-2) break;
                    for (int j = i+k+1; j < arr.length; j++) {
                        if((j+kk) > arr.length) break;
                        String o = j + "";
                        String t = (j+kk) + "";
                        String key2 = o + " " + t;
                        long last = 0;
                        if(map.containsKey(key2)) {
                            //System.out.println("Key 2 found!");
                            last = map.get(key2).longValue();
                        } else {
                            last = sum(j, j+kk);
                            map.put(key2, new Long(last));
                        }
                        if (((first+last) % divide) == 0) {
                            numchomps++;
                        }
                    }
                    kk++;
                }
            }
            k++;
        }
        return numchomps;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        int n = Integer.parseInt(in.nextLine());
        for(int i = 1; i <= n; i++) {
            int length = in.nextInt();
            long divide = in.nextLong();
            in.nextLine();
            arr = new long[length];
            for(int j = 0; j < length; j++) {
                arr[j] = (in.nextLong());
            }
            //System.out.println(arr);
            in.nextLine();
            long blah = numChomps(arr, divide);
            System.out.println("Plate #"+i + ": " + blah);
        }

    }

}

我的代码得到了正确的答案,但似乎花费的时间太长,尤其是对于数组大小为 1000 或更大的大型输入。我试图提高算法的速度,我存储以前在HashMap 中计算的总和,但这并没有显着提高我的程序的速度。我可以做些什么来提高速度,使其在 10 秒内运行?

【问题讨论】:

    标签: java algorithm performance


    【解决方案1】:

    效率低下的第一个来源是不断重新计算总和。你应该创建一个部分和的辅助数组long [n] partial;,然后你可以简单地调用partial[i + k] - partial[i],而不是调用sum(i, i + k)

    现在问题减少到找到索引i&lt;j&lt;k&lt;m 这样

        (partial[j] - partial[i] + partial[m] - partial[k]) % divide == 0
    

    或者,重新排列术语,

        (partial[j] + partial[m]) % divide == (partial[i] + partial[k]) % divide 
    

    要找到它们,您可以考虑一个三元组数组(s, i, j) 其中s = (partial[j] - partial[i]) % divide,按s 对其进行稳定排序,并检查非重叠“chomps”的相等范围。

    这种方法将性能从 O(n4) 提高到 O(n2 log n)。现在你应该能够将它改进到 O(n log n)。

    【讨论】:

    • 我有一个哈希图来存储以前计算的值,为什么要使用数组?
    猜你喜欢
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多