贪心算法需求

76 阅读3分钟

贪心算法需求

  1. 给定一个任务调度问题,每个任务有一个开始时间、结束时间和收益,使用贪心算法找到能获得最大收益的任务子集,且任务之间不能有时间冲突。
  2. 有一个背包,背包容量为 C,每个物品有重量 w 和价值 v,利用贪心算法确定在不超过背包容量的情况下,能装入背包的物品组合,使得总价值最大(这里可以是 0-1 背包问题或者部分背包问题)。
  3. 在一个图中,每个边有一个权重,使用贪心算法实现最小生成树算法(如 Prim 算法或 Kruskal 算法),找到连接图中所有顶点的边的子集,使得这些边的权重之和最小。
  4. 有一组活动,每个活动有一个开始时间和结束时间,利用贪心算法找到能在一个时间段内安排最多活动的方案。
  5. 对一个整数数组进行排序,使用贪心算法将数组中的元素分成若干组,使得每组元素的和尽可能接近。

1. 任务调度问题

任务调度问题需要找到能获得最大收益的任务子集,且任务之间不能有时间冲突。我们可以先按结束时间对任务进行排序,然后依次选择不冲突的任务。 def job_scheduling(start_time, end_time, profit): jobs = sorted(zip(start_time, end_time, profit), key=lambda x: x[1]) n = len(jobs) dp = [0] * n dp[0] = jobs[0][2]

for i in range(1, n):
    incl_prof = jobs[i][2]
    l = 0
    r = i - 1
    last_non_conflict = -1
    while l <= r:
        mid = (l + r) // 2
        if jobs[mid][1] <= jobs[i][0]:
            last_non_conflict = mid
            l = mid + 1
        else:
            r = mid - 1
    if last_non_conflict != -1:
        incl_prof += dp[last_non_conflict]
    dp[i] = max(incl_prof, dp[i - 1])

return dp[-1]

示例使用

start_time = [1, 2, 3, 4, 6] end_time = [3, 5, 9, 6, 9] profit = [20, 20, 100, 70, 60] print(job_scheduling(start_time, end_time, profit))

2. 背包问题

这里我们实现部分背包问题,按单位重量价值对物品进行排序,然后依次选择单位重量价值高的物品。 def fractional_knapsack(capacity, weights, values):

items = [(v / w, w, v) for w, v in zip(weights, values)]
items.sort(reverse=True)
total_value = 0
for ratio, weight, value in items:
    if capacity == 0:
        return total_value
    amount = min(weight, capacity)
    total_value += amount * ratio
    capacity -= amount
return total_value

示例使用

capacity = 50 weights = [10, 20, 30] values = [60, 100, 120] print(fractional_knapsack(capacity, weights, values))

3. 最小生成树问题(Kruskal 算法)

Kruskal 算法通过按边的权重排序,然后依次选择不形成环的边来构建最小生成树。 class UnionFind: def init(self, n): self.parent = list(range(n)) self.rank = [0] * n

def find(self, x):
    if self.parent[x] != x:
        self.parent[x] = self.find(self.parent[x])
    return self.parent[x]

def union(self, x, y):
    root_x = self.find(x)
    root_y = self.find(y)
    if root_x != root_y:
        if self.rank[root_x] > self.rank[root_y]:
            self.parent[root_y] = root_x
        elif self.rank[root_x] < self.rank[root_y]:
            self.parent[root_x] = root_y
        else:
            self.parent[root_y] = root_x
            self.rank[root_x] += 1
        return True
    return False

def kruskal(edges, n): edges.sort(key=lambda x: x[2]) uf = UnionFind(n) mst = [] for u, v, w in edges: if uf.union(u, v): mst.append((u, v, w)) return mst

示例使用

edges = [(0, 1, 10), (0, 2, 6), (0, 3, 5), (1, 3, 15), (2, 3, 4)] n = 4 print(kruskal(edges, n))

4. 活动选择问题

活动选择问题需要找到能在一个时间段内安排最多活动的方案。我们可以按结束时间对活动进行排序,然后依次选择不冲突的活动。

def activity_selection(start, end):

activities = sorted(zip(start, end), key=lambda x: x[1])
result = []
i = 0
result.append(activities[i])
for j in range(1, len(activities)):
    if activities[j][0] >= activities[i][1]:
        result.append(activities[j])
        i = j
return result

示例使用

start = [1, 3, 0, 5, 8, 5] end = [2, 4, 6, 7, 9, 9] print(activity_selection(start, end))

5. 数组分组问题

将数组中的元素分成若干组,使得每组元素的和尽可能接近。我们可以先对数组进行排序,然后依次将元素添加到和最小的组中。

def group_array(arr, num_groups): arr.sort(reverse=True) groups = [[] for _ in range(num_groups)] sums = [0] * num_groups

for num in arr:
    min_index = sums.index(min(sums))
    groups[min_index].append(num)
    sums[min_index] += num

return groups

示例使用

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9] num_groups = 3 print(group_array(arr, num_groups))