欲張りアルゴリズム(欲張りアルゴリズム)

本旨

問題を解くとき、各ステップは最終的にグローバルな最適解を得ることを期待してローカルな最適解を選択します。
(欲張りアルゴリズムの最終結果は、必ずしもグローバルな最適解ではありませんが、実際にはおおよその最適解です。)


古典的な問題1-集合被覆問題

n個のセットがあり、各セットにはいくつかの要素が含まれています。それらからm個のセットを見つけるには、n個のセットにすべての要素が含まれている必要があり、mが最小です。
一般的な解決策:
(1)nセットのすべての組み合わせをリストします。これは、各セットがセットに含まれる場合と含まれない場合があるため、合計2 n 2 ^ nになるためです。2n種類の組み合わせスキーム。
(2)これらの組み合わせスキームで、すべての要素を含むセットの組み合わせを見つけ、その組み合わせに含まれるセットの数が最も少なくなります。

この方法の時間計算量はO(2 n)O(2 ^ n)です。O 2n、nが増加すると、時間は急激に増加し、使用できなくなります。

欲張りアルゴリズムのアイデア(近似アルゴリズム):(
1)最も含まれていない要素を含むセットを選択します。
(2)選択したセットにすべての要素が含まれるまで、最初の手順を繰り返します。

欲張りアルゴリズムの時間計算量はO(n 2)O(n ^ 2)です。O n2
例:
次のようにいくつかのセットがあり
ます
。set1= {1、2、3};
set2 = {1、3、4};set3 = {2、5、6};set4 = {2、3}を
解きます。;
set5 = {6、7};

コード:

public class GreedyAlgorithm {
    
    
    public Set<Integer> greedy(List<Set<Integer>> setList) {
    
    
    	//收集所有集合中的所有元素
        Set<Integer> needed = new HashSet<>();
        for (Set<Integer> set : setList) {
    
    
            for (int i : set) {
    
    
                needed.add(i);
            }
        }
        Set<Integer> result = new HashSet<>();
        while (!needed.isEmpty()) {
    
    
            int bestSet = 0;
            int bestCoveredSize = 0;
            for (int i = 0; i < setList.size(); i++) {
    
    
            	if (result.contains(i)) {
    
    
                    continue;
                }
                int coveredSize = 0;
                for (int j : setList.get(i)) {
    
    
                    if (needed.contains(j)) {
    
    
                        coveredSize++;
                    }
                }
                //体现出贪心算法,每次都选含有最多未包含元素的集合
                if (coveredSize > bestCoveredSize) {
    
    
                    bestSet = i;
                    bestCoveredSize = coveredSize;
                }
            }
            result.add(bestSet);
            needed.removeAll(setList.get(bestSet));

        }
        return result;
    }

    public static void main(String[] args) {
    
    
        List<Set<Integer>> setList = new ArrayList<>();
        setList.add(new HashSet<>(Arrays.asList(1, 2, 3)));
        setList.add(new HashSet<>(Arrays.asList(1, 3, 4)));
        setList.add(new HashSet<>(Arrays.asList(2, 5, 6)));
        setList.add(new HashSet<>(Arrays.asList(2, 3)));
        setList.add(new HashSet<>(Arrays.asList(6, 7)));
        System.out.println(new GreedyAlgorithm().greedy(setList));
    }
}

古典的な問題2-巡回セールスマン問題

A市から他のn都市への移動が必要な旅行代理店があります。総移動距離が最短になるように旅行ルートを計画してください。

一般的な解決策:n!N!を
計算します。n 移動ルートを選択し、その中から最短ルートを選択します。時間計算量はO(n!)O(n!)です。O n

欲張りアルゴリズムのアイデア:
行きたい次の都市を選択するたびに、行ったことのない最も近い都市を選択します。

コード

public class GreedyAlgorithm2 {
    
    
    public static int[] greedyAlgorithm2(int[][] distance, int n) {
    
    
        int[] result = new int[n];
        Set<Integer> notBeenTo = new HashSet<>(n);
        for (int i = 1; i <= n; i++) {
    
    
            notBeenTo.add(i);
        }

        int from = 0;
        for (int i = 0; i < result.length; i++) {
    
    
            int next = 0;
            for (int j : notBeenTo) {
    
    
                //体现出贪心算法,每次都选还没去过的距离最近的城市
                if (next == 0 || distance[from][next] > distance[from][j]) {
    
    
                    next = j;
                }
            }
            result[i] = next;
            from = next;
            notBeenTo.remove(next);
        }

        return result;
    }

    //测试代码
    public static void main(String[] args) {
    
    
        int n = 4;
        int[][] distance = new int[n + 1][n + 1];
        //0表示旅行商当前所在城市A, 1...n表示要去的城市
        Random rnd = new Random();
        for (int i = 0; i < distance.length; i++) {
    
    
            for (int j = 0; j < i; j++) {
    
    
                if (i != j) {
    
    
                    distance[i][j] = distance[j][i] = rnd.nextInt(10) + 1;
                }
            }
        }
        for (int[] arr : distance) {
    
    
            System.out.println(Arrays.toString(arr));
        }
        System.out.println();
        int[] result = greedyAlgorithm2(distance, n);
        System.out.println(Arrays.toString(result));
    }
}

NP完全問題

P問題、NP問題、NP完全問題(NPC)、NP困難問題(NPH)とは、Baiduだけでお願いしますが、満足のいく答えが見つかりませんでした(理解できませんでした)。

  • NP完全問題の簡単な定義は、集合被覆問題や巡回セールスマン問題など、解決が難しい問題(多項式時間では解決できない問題)として知られています。
  • 問題がNP完全であると判断する場合、完全な解決策を見つける必要はありませんが、近似アルゴリズムを使用する必要があります。しかし、問題がNP完全であるかどうかを判断することは困難です。これは、解決が容易な問題とNP完全問題の差が通常非常に小さいためです。「2点間の最短経路問題」や「巡回セールスマン問題」など。

次の方法は、問題がNP完全であるかどうかを単純に(必ずしも)判断するために使用できます。

  • 要素の数が少ない場合、アルゴリズムは非常に高速に実行されますが、要素の数が増えると、速度は非常に遅くなります。
  • 「すべての組み合わせ」に関連する問題は、通常、NP完全です。
  • 問題を小さな問題に分割することはできません。考えられるすべての状況を考慮する必要があります。これはNP完全問題である可能性があります。
  • 問題がシーケンス(巡回セールスマン問題の都市シーケンスなど)に関係していて、解決が難しい場合は、NP完全問題である可能性があります。
  • 問題がコレクション(放送局のコレクションなど)に関係していて、解決が難しい場合は、NP完全問題である可能性があります。
  • 問題が集合被覆問題または旅行者問題に変換できる場合、それはNP完全でなければなりません。

参照:「アルゴリズム図」第8章欲張りアルゴリズム

おすすめ

転載: blog.csdn.net/AmorFati1996/article/details/110998879