暴力求解系列之簡單枚舉

題目來自劉汝佳的《算法競賽入門經典(第二版)》,下面實現代碼均爲Java

簡單枚舉

問題1:

  輸入正整數nn, 按從小到大的順序輸出所有形如abcde/fghij=nabcde/fghij = n的表達式, 其中aja~ j恰好爲數字090~ 9的一個排列(可以有前導0),其中2n792≤n≤79
解題思路:直接枚舉所有090~ 9的所有排列,枚舉量爲10!=362880010!=3628800,可以只枚舉fghijfghij,枚舉量下降至不到10萬
下面是枚舉fghijfghij的兩種解法:
解法1是直接枚舉100010004999949999的所有數,枚舉會有重複元素,枚舉量爲4萬+;
解法2是遞歸枚舉(解答樹),沒有枚舉重複元素,枚舉量爲109876=3024010*9*8*7*6=30240

public class Division {
    /**
     * 算法1實現
     * @param n 正整數
     * @return  所有滿足abcde/fghij = n的abcdefghij列表
     */
    private List<String> solver1(int n){
        List<String> results = new ArrayList<>();
        for(Integer i = 1000;i<=49999;i++){
            String divisor  = new String(i.toString());
            if(divisor.length() < 5){
                divisor = "0" + divisor;
            }
            String dividend = new String(new Integer(i*n).toString());
            /* 如果位數共大於10 */
            if(dividend.length() + divisor.length() > 10){
                continue;
            }
            Set<Character> countSet = new HashSet<>();
            for(int j = 0;j<dividend.length();j++){
                countSet.add(dividend.charAt(j));
            }
            if(countSet.size() < 5){
                continue;
            }
            for(int j = 0;j<divisor.length();j++){
                countSet.add(divisor.charAt(j));
            }
            if(countSet.size() == 10){
                results.add(dividend + "/" + divisor + "=" + n);
            }
        }
        return results;
    }
    /**
     * 算法2實現:遞歸枚舉
     * @param n 輸入
     * @param results 保存所有結果
     * @param temp 輔助數組,記錄當前已經用過的元素
     * @param cur 記錄當前已經用過的元素個數
     */
    private void solver2(int n, List<String> results, Integer[] temp, int cur){
        if(cur == 5){
            String s = "";
            Set<Integer> countSet = new HashSet<>(Arrays.asList(temp));
            for(int i = 0;i<5;i++){
                s += temp[i];
            }
            String dividend = new Integer(Integer.parseInt(s) * n).toString();
            if(dividend.length() == 5){
                for(int j = 0;j<dividend.length();j++){
                    countSet.add(Integer.parseInt(dividend.substring(j,j+1)));
                }
                if(countSet.size() == 10){
                    results.add(dividend + "/" + s + "=" + n);
                }
            }
        }else{
            for(int i = 0;i<=9;i++){
                boolean flag = true;
                for(int j = 0;j<cur;j++){
                    if(temp[j] == i){
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    temp[cur] = i;
                    solver2(n, results, temp, cur+1);
                }
            }
        }
    }
   /**
     * 輸出結果
     */
    public void solution(){
        int n = 3;
        /* 解法1 */
        for(String s:solver1(n)){
            System.out.println(s);
        }
        System.out.println();
        /* 解法2 */
        List<String> results = new ArrayList<>();
        Integer[] temp = new Integer[5];
        Arrays.fill(temp, -1);
        solver2(n, results, temp, 0);
        for(String s:results){
            System.out.println(s);
        }

    }
    public static void main(String[] args){
        Division division = new Division();
        division.solution();
    }
}

在這裏插入圖片描述

問題2:

  輸入正整數kk, 找到所有的正整數xyx \geq y,使得 1k=1x+1y\frac{1}{k} = \frac{1}{x}+\frac{1}{y}
解題思路:首先發現x=y=2kx=y=2k時等式成立,因此只要枚舉k&lt;y2kk&lt; y\leq2k即可,根據kkyy判斷求出的x=kyykx=\frac{k*y}{y-k}是否爲整數

/**
     * 算法實現
     * @param k 正整數k
     * @return 所有滿足1/k = 1/x + 1/y的x和y的列表
     */
    private List<int[]> solver1(int k){
        List<int[]> results = new ArrayList<>();
        /* 枚舉y */
        for(int y = k+1;y<=2*k;y++){
            double temp = (double) k*y/(y-k);
            if(temp == (int) temp){
                results.add(new int[]{(int) temp, y});
            }
        }
        return results;
    }
    /**
     * 輸出結果
     */
    public void solution(){
    	/* 輸入 */
        int k = 12;
        for(int[] result:solver1(k)){
            System.out.println("1/" + result[0] + " + " + "1/" + result[1] + " = " + "1/" + k);
        }
    }
    public static void main(String[] args){
        Fractions fractions = new Fractions();
        fractions.solution();
    }

在這裏插入圖片描述

問題3:

  輸入nn個元素組成的序列SS, 你需要找出一個乘積最大的連續子序列。 如果這個最大的乘積不是正數, 應輸出00。 其中1n181≤n≤1810Si10-10≤S_i≤10
解題思路:直接枚舉起點ii到終點jj的乘積,找出最大值即可(雖然所有元素的絕對值都小於等於10,其最大乘積可能會溢出,這裏我沒管了= =)

public class MaxmiumProduct {
    /**
     * 算法實現
     * @param a 包含所有元素
     * @return  連續子序列最大乘積
     */
    private long solver1(int[] a){
        int n = a.length;
        long[][] product = new long[n][n];
        long maxProduct = 0;
        for(int i = 0;i<n;i++){
            long tempProduct = 1L;
            for(int j = i;j<n;j++){
                product[i][j] = tempProduct *= a[j];
                if(maxProduct < product[i][j]){
                    maxProduct = product[i][j];
                }
            }
        }
        return maxProduct;
    }
    /**
     * 輸出結果
     */
    public void solution(){
    	/* 輸入 */
        int a[] = new int[]{2, 4, -3, 2, 0, -2, -4, -8, 0, 4, 9, -5, -10} ;
        System.out.println(solver1(a));
    }
    public static void main(String[] args){
        MaxmiumProduct maxmiumProduct = new MaxmiumProduct();
        maxmiumProduct.solution();
    }
}

在這裏插入圖片描述
有任何問題,歡迎指出 :)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章