Greedy

1. Activity Selection (활동 선택 문제)

  • 문제: 주어진 활동 중 서로 겹치지 않는 최대 개수의 활동을 선택합니다.

  • 아이디어: 종료 시간이 빠른 활동을 먼저 선택하는 것이 최적입니다.

class Activity {
    int start, finish;

    Activity(int start, int finish) {
        this.start = start;
        this.finish = finish;
    }
}

void activitySelection(List<Activity> activities) {
    // 종료 시간을 기준으로 활동 정렬
    activities.sort((a, b) -> a.finish - b.finish);

    // 첫 번째 활동 선택
    int lastFinishTime = activities.get(0).finish;
    System.out.println("Selected Activity: " + activities.get(0).start + " - " + activities.get(0).finish);

    // 각 활동을 확인하면서 종료 시간이 겹치지 않는 활동 선택
    for (int i = 1; i < activities.size(); i++) {
        if (activities.get(i).start >= lastFinishTime) {
            System.out.println("Selected Activity: " + activities.get(i).start + " - " + activities.get(i).finish);
            lastFinishTime = activities.get(i).finish;
        }
    }
}

2. Fractional Knapsack (부분 배낭 문제)

  • 문제: 주어진 배낭에 최대한 많은 가치를 담으면서 무게 제한을 넘지 않도록 합니다.

  • 아이디어: 가치 대비 무게 비율이 높은 물건을 우선적으로 담습니다.

class Item {
    int weight;
    int value;

    Item(int weight, int value) {
        this.weight = weight;
        this.value = value;
    }
}

void fractionalKnapsack(int capacity, List<Item> items) {
    // 가치 대비 무게 비율을 기준으로 아이템 정렬
    items.sort((a, b) -> Double.compare((double) b.value / b.weight, (double) a.value / a.weight));

    double totalValue = 0;

    for (Item item : items) {
        if (capacity > 0 && item.weight <= capacity) {
            // 물건을 배낭에 전부 담을 수 있는 경우
            capacity -= item.weight;
            totalValue += item.value;
        } else {
            // 물건을 부분적으로 담아야 하는 경우
            totalValue += item.value * ((double) capacity / item.weight);
            break;
        }
    }

    System.out.println("Maximum value we can obtain: " + totalValue);
}

3. 최소 동전 문제 (Coin Change Problem, 최소 개수)

  • 문제: 주어진 금액을 만들기 위해 최소한의 동전을 사용하는 방법을 찾습니다.

  • 아이디어: 큰 동전부터 사용하여 금액을 채웁니다.

void coinChange(int[] coins, int amount) {
    Arrays.sort(coins);  // 동전을 오름차순으로 정렬
    int count = 0;

    for (int i = coins.length - 1; i >= 0; i--) {
        if (amount == 0) break;
        if (coins[i] <= amount) {
            count += amount / coins[i];  // 현재 동전으로 만들 수 있는 금액
            amount %= coins[i];  // 남은 금액
        }
    }

    if (amount > 0) {
        System.out.println("Cannot make the amount with given coins.");
    } else {
        System.out.println("Minimum coins required: " + count);
    }
}

4. 회의실 배정 문제

  • 문제: 여러 회의가 있을 때, 하나의 회의실에서 가장 많은 회의를 진행할 수 있도록 회의를 선택합니다.

  • 아이디어: 종료 시간이 가장 빠른 회의를 먼저 선택합니다.

class Meeting {
    int start, end;

    Meeting(int start, int end) {
        this.start = start;
        this.end = end;
    }
}

void meetingRoomAllocation(List<Meeting> meetings) {
    meetings.sort((a, b) -> a.end - b.end);  // 종료 시간을 기준으로 정렬

    int lastEndTime = -1;
    int count = 0;

    for (Meeting meeting : meetings) {
        if (meeting.start >= lastEndTime) {
            lastEndTime = meeting.end;
            count++;
        }
    }

    System.out.println("Maximum number of meetings: " + count);
}

5. Job Scheduling Problem (작업 스케줄링 문제)

  • 문제: 각 작업은 특정 시간이 지나면 수행할 수 없으며, 작업이 주어진 기한 내에 완료될 때 보상을 받습니다. 최대 보상을 받는 스케줄을 선택합니다.

  • 아이디어: 보상이 높은 작업을 우선적으로 기한 내에 배치합니다.

class Job {
    int deadline, profit;

    Job(int deadline, int profit) {
        this.deadline = deadline;
        this.profit = profit;
    }
}

void jobScheduling(List<Job> jobs, int maxDeadline) {
    jobs.sort((a, b) -> b.profit - a.profit);  // 보상을 기준으로 정렬

    boolean[] slots = new boolean[maxDeadline];
    int totalProfit = 0;

    for (Job job : jobs) {
        for (int j = Math.min(maxDeadline - 1, job.deadline - 1); j >= 0; j--) {
            if (!slots[j]) {
                slots[j] = true;
                totalProfit += job.profit;
                break;
            }
        }
    }

    System.out.println("Maximum profit: " + totalProfit);
}

6. 최소 신장 트리 (Kruskal's Algorithm)

  • 문제: 주어진 그래프에서 최소 신장 트리를 구합니다.

  • 아이디어: 간선의 가중치가 낮은 순서대로 추가하면서 사이클이 생기지 않도록 합니다.

class Edge {
    int src, dest, weight;

    Edge(int src, int dest, int weight) {
        this.src = src;
        this.dest = dest;
        this.weight = weight;
    }
}

class UnionFind {
    int[] parent, rank;

    UnionFind(int n) {
        parent = new int[n];
        rank = new int[n];
        for (int i = 0; i < n; i++) parent[i] = i;
    }

    int find(int u) {
        if (parent[u] != u) parent[u] = find(parent[u]);
        return parent[u];
    }

    void union(int u, int v) {
        int rootU = find(u);
        int rootV = find(v);

        if (rootU != rootV) {
            if (rank[rootU] > rank[rootV]) {
                parent[rootV] = rootU;
            } else if (rank[rootU] < rank[rootV]) {
                parent[rootU] = rootV;
            } else {
                parent[rootV] = rootU;
                rank[rootU]++;
            }
        }
    }
}

void kruskalMST(List<Edge> edges, int vertices) {
    edges.sort((a, b) -> a.weight - b.weight);
    UnionFind uf = new UnionFind(vertices);

    int mstWeight = 0;
    List<Edge> mst = new ArrayList<>();

    for (Edge edge : edges) {
        if (uf.find(edge.src) != uf.find(edge.dest)) {
            uf.union(edge.src, edge.dest);
            mst.add(edge);
            mstWeight += edge.weight;
        }
    }

    System.out.println("Total weight of MST: " + mstWeight);
}

Last updated