貪欲なアルゴリズムの例

        

目次

貪欲なアルゴリズム

問題を変える

最高額

果物の山


貪欲なアルゴリズム

        貪欲アルゴリズム (貪欲アルゴリズム)、貪欲なアルゴリズムとも呼ばれます) は、問題を解決するときに、常に現時点で最良の選択を行うことを意味します。つまり、全体の最適性を考慮せずに、アルゴリズムはある意味で局所的な最適解を求めます。貪欲なアルゴリズムは、すべての問題に対して全体的な最適解を得ることはできません。重要なのは、貪欲な戦略の選択です。

問題を変える

通貨: 1 2 4 5 10 数枚、小銭: n 元。出力変更スキーム

アイデア:

(1) 貪欲は最適解を見つけることなので、最大の通貨価値を探し始める必要があります

(2) 条件を満たす通貨値が見つかるたびに、見つかった金額を n から減算し、n が 0 以下になるまでループを続けて停止します。

import java.util.Scanner;

public class Greed {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        greedy(n);
    }

    public static void greedy(int n) {
        int[] money = {
    
    10, 5, 4, 2, 1};//钱的面值,从大到小,因为要找最优解。
        int i = 0;//表示目前用money数组中哪一个面值的钱去找零,最开始从10快开始。
        int[] num = new int[money.length];
        while (n > 0) {
    
    //n>0说明钱还没有找完,所以继续循环
            if (n >= money[i]) {
    
    //剩余要找的钱必须大于等于当前money[i]这个面值
                int zs = n / money[i];
                n -= zs * money[i];
                num[i]+= zs;//当前这个面值的数量加上zs
            } else{
    
    //如果当前面值不能找开就i++
                i++;
            }
        }
        for (int j = 0; j < num.length; j++) {
    
    //输出
            if (num[j] > 0) {
    
    //说明当前这个面值的钱使用到了,所以才能输出
                System.out.printf("面值:%d 张数:%d ", money[j], num[j]);
            }
        }
    }
}

           


最高額

        整数 n が現在の賞金プールに既にある合計金額を表す場合、n から m 個の数字を削除し、残りの値に対応する金額は、奪うことができるお金です. 私たちは人間の本性が貪欲であることを知っているので、シャオミンが作るのを手伝ってください元の順序の残りの数によって形成される新しい数が最大です。

たとえば、n = 92081346718538、m = 10 の場合、新しい最大数は 9888 です。

サンプル入力:

92081346718538 10

1008908 5

出力例:

9888

98

アイデア:

(1) まず削除問題を保持問題に変え、欲張りな発想で非予約数外の最大値を毎回探す

(2) 入力が 92081346718538 10 だとすると、14 個の数字のうち 10 個を削除する必要があるため、最初の 11 個の数字の中から最大値を選択し、次のサイクルではこの最大値から 12 個目の数字までを検索します。最大数、for ループの i が予約済みの数と等しくなるまで、停止します。

import java.util.Scanner;

public class selectMaxNumber {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String n = scanner.next();//输入n为String类型
            int m = scanner.nextInt();//输入需要删除数的个数
            if (n.length() <= m) {
                System.out.println("输入错误,请重新输入");
            }
            char[] a = n.toCharArray();//将String类型的数转为char数组,为了循环判断使用
            String max = "";//定义max变量存放最后早到的最大数
            int retain = a.length - m;//将删除问题变成保留问题
            int lastselect = -1;//存放最大数在数组中的位置,开始的时候定义为-1,在循环时在+1就从0开始了
            for (int i = 1; i <= retain; i++) {
                char big = '0';//循环比较前先假设big为最小的值
                    for (int j = lastselect + 1; j < a.length - (retain - i); j++) {
                    //这里lastselect+1主要是因为在找到一个最大的数后下次循环就从这个最大数的下一个开始
                    /*
                    j < a.length - (retain - i)这个区间判断方法是
                    第一次循环判断的范围是j < 11,也就是0到10,因为总共有14个数,需要保留四个,
                    所以第一次就需要在前11个中选择一个最大的数,然后每次循环结束范围都要往后移一位
                    例如:92081346718538删掉十个数,第一次循环判断在92081346718中
                    第二次循环判断在20813467185中,第三次在134671853中,第四次就在538中
                     */

                    if (a[j] > big) {
                        big = a[j];
                        lastselect = j;//找到大的数就将j赋给存放最大数地址的这个变量
                    }
                }
                max += big;//每次找出那个最大的数后就拼接到max中
            }
            System.out.println(max);
        }
    }
}

 


果物の山

        果樹園で、Duoduo はすでにすべての果物を倒し、さまざまな種類の果物に応じてさまざまな山に分けました.Duoduo はすべての果物を組み合わせて山にすることにしました.Duoduo は、マージするたびに、2 つの果物の山を一緒にマージできます.消費される体力は、果物の山2つの重さの合計に等しい。n-1 回すべての果実を融合させた後、残っている山は 1 つだけであることがわかります.果実を融合するときに Duoduo が消費する体力の合計は、各融合で消費される体力の合計に等しくなります。

        これらの果物を家に持ち帰るには多大な労力がかかるため、Duoduo は果物をマージするときにできるだけエネルギーを節約する必要があります. 各果物の重さは 1 であり、果物の種類の数と各果物の数がわかっていると仮定すると、タスクは、Duoduo が消費するエネルギーを最小化するための組み合わせシーケンス プランを設計し、最小エネルギーの値を出力することです。

入力: 最初の行: 果物の種類の数を示す整数 n (1<=n<=100)。2 行目: スペースで区切られた n 個の整数が含まれます。n が 0 のときに自動的に終了する

アイデア:

(1) n==0 の場合は停止し、n==1 の場合は重量を直接出力します。

(2) n>1 の場合、ループし、最初に配列を小さいものから大きいものへと並べ替え、次に配列の最初の数と 2 番目の数を各サイクルで加算し、空いている位置を無限大にすることで、位相加算をループできるようにします。 .

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

public class pileFruit {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();//输入果子总共的堆数
            int[] m = new int[n];//表示n堆果子重量的数组
            if (n == 0) break;//n==0时直接结束
            if (n == 1) {
                //如果只有一堆果子,就直接输出这堆果子的重量
                System.out.println(scanner.nextInt());
                continue;
            }
            for (int i = 0; i < n; i++) {
                m[i] = scanner.nextInt();//输入每堆果子的重量
            }
            int sum = 0;//记录总共搬运的重量
            for (int i = 0; i < n - 1; i++) {//循环n-1次,例如三堆果子只需要搬2次
                Arrays.sort(m);//将m数组排序
                sum = sum + m[0] + m[1];//先从最轻的开始合并
                m[0] += m[1];//搬完后m[0]就表示合并后的重量
                m[1] = Integer.MAX_VALUE;//然后m[1]给无穷大,这样每次循环就会到数组最后
                System.out.println(Arrays.toString(m));//查看数组数的排序
            }
            System.out.println(sum);
        }
    }
}

 各ソート前の配列が出力され、最後に消費された総エネルギーも出力されていることがわかります。

 

おすすめ

転載: blog.csdn.net/weixin_71646897/article/details/129768164