📜  活动选择问题 |贪婪算法-1

📅  最后修改于: 2021-10-26 05:26:50             🧑  作者: Mango

Greedy 是一种算法范式,它逐个构建解决方案,始终选择下一个提供最明显和直接好处的部分。贪心算法用于优化问题。如果问题具有以下性质,则可以使用 Greedy 解决优化问题:在每一步,我们都可以做出当前看起来最好的选择,从而得到整个问题的最优解
如果贪心算法可以解决问题,那么它通常会成为解决该问题的最佳方法,因为贪心算法通常比动态规划等其他技术更有效。但是贪心算法并不总是适用。例如,分数背包问题可以使用 Greedy 解决,但 0-1 Knapsack 问题无法使用 Greedy 解决。
以下是一些标准算法,即贪婪算法。
1) Kruskal 的最小生成树 (MST) 在 Kruskal 的算法中,我们通过一一选取边来创建 MST。贪婪的选择是选择在目前构造的 MST 中不会导致循环的最小权重边。
2) Prim 的最小生成树在 Prim 的算法中,我们也通过一一选择边来创建 MST。我们维护两个集合:一组已包含在 MST 中的顶点和一组尚未包含的顶点。贪心选择是选择连接两组的最小权重边。
3) Dijkstra 的最短路径 Dijkstra 的算法与 Prim 的算法非常相似。最短路径树是边接边构建的。我们维护两个集合:一组已经包含在树中的顶点和一组尚未包含的顶点。 Greedy Choice 是选择连接两个集合并且在从源到包含尚未包含的顶点的集合的最小权重路径上的边。
4)霍夫曼编码霍夫曼编码是一种无损压缩技术。它将可变长度的位代码分配给不同的字符。贪婪的选择是为出现频率最高的字符分配最少的位长代码。
贪心算法有时也用于获得硬优化问题的近似值。例如,旅行商问题是一个 NP-Hard 问题。这个问题的一个贪心选择是在每一步都选择离当前城市最近的未访问城市。这些解决方案并不总是产生最佳最优解决方案,但可用于获得近似最优解决方案。
让我们将活动选择问题视为贪婪算法的第一个示例。以下是问题陈述。
您将获得 n 个活动及其开始和结束时间。选择一个人可以执行的最大活动数,假设一个人一次只能从事一项活动。

例子:

Example 1 : Consider the following 3 activities sorted by
by finish time.
     start[]  =  {10, 12, 20};
     finish[] =  {20, 25, 30};
A person can perform at most two activities. The 
maximum set of activities that can be executed 
is {0, 2} [ These are indexes in start[] and 
finish[] ]

Example 2 : Consider the following 6 activities 
sorted by by finish time.
     start[]  =  {1, 3, 0, 5, 8, 5};
     finish[] =  {2, 4, 6, 7, 9, 9};
A person can perform at most four activities. The 
maximum set of activities that can be executed 
is {0, 1, 3, 4} [ These are indexes in start[] and 
finish[] ]

贪心选择是总是在剩余的活动中选择完成时间最短的下一个活动,并且开始时间大于或等于之前选择的活动的完成时间。我们可以根据活动的完成时间对活动进行排序,以便我们始终将下一个活动视为最短完成时间的活动。
1) 根据活动完成时间对活动进行排序
2) 从排序后的数组中选择第一个活动并打印它。
3) 对排序数组中的剩余活动执行以下操作。
…….a) 如果此活动的开始时间大于或等于先前选定活动的完成时间,则选择此活动并打印。
在下面的 C 实现中,假设活动已经根据它们的完成时间排序。

C++
// C++ program for activity selection problem.
// The following implementation assumes that the activities
// are already sorted according to their finish time
#include 
using namespace std;
 
// Prints a maximum set of activities that can be done by a single
// person, one at a time.
//  n   -->  Total number of activities
//  s[] -->  An array that contains start time of all activities
//  f[] -->  An array that contains finish time of all activities
void printMaxActivities(int s[], int f[], int n)
{
    int i, j;
 
    cout <<"Following activities are selected "<< endl;
 
    // The first activity always gets selected
    i = 0;
    cout <<" "<< i;
 
    // Consider rest of the activities
    for (j = 1; j < n; j++)
    {
      // If this activity has start time greater than or
      // equal to the finish time of previously selected
      // activity, then select it
      if (s[j] >= f[i])
      {
          cout <<" " << j;
          i = j;
      }
    }
}
 
// driver program to test above function
int main()
{
    int s[] =  {1, 3, 0, 5, 8, 5};
    int f[] =  {2, 4, 6, 7, 9, 9};
    int n = sizeof(s)/sizeof(s[0]);
    printMaxActivities(s, f, n);
    return 0;
}
//this code contributed by shivanisinghss2110


C
// C program for activity selection problem.
// The following implementation assumes that the activities
// are already sorted according to their finish time
#include
 
// Prints a maximum set of activities that can be done by a single
// person, one at a time.
//  n   -->  Total number of activities
//  s[] -->  An array that contains start time of all activities
//  f[] -->  An array that contains finish time of all activities
void printMaxActivities(int s[], int f[], int n)
{
    int i, j;
 
    printf ("Following activities are selected n");
 
    // The first activity always gets selected
    i = 0;
    printf("%d ", i);
 
    // Consider rest of the activities
    for (j = 1; j < n; j++)
    {
      // If this activity has start time greater than or
      // equal to the finish time of previously selected
      // activity, then select it
      if (s[j] >= f[i])
      {
          printf ("%d ", j);
          i = j;
      }
    }
}
 
// driver program to test above function
int main()
{
    int s[] =  {1, 3, 0, 5, 8, 5};
    int f[] =  {2, 4, 6, 7, 9, 9};
    int n = sizeof(s)/sizeof(s[0]);
    printMaxActivities(s, f, n);
    return 0;
}


Java
// The following implementation assumes that the activities
// are already sorted according to their finish time
import java.util.*;
import java.lang.*;
import java.io.*;
 
class ActivitySelection
{
    // Prints a maximum set of activities that can be done by a single
    // person, one at a time.
    //  n   -->  Total number of activities
    //  s[] -->  An array that contains start time of all activities
    //  f[] -->  An array that contains finish time of all activities
    public static void printMaxActivities(int s[], int f[], int n)
    {
    int i, j;
      
    System.out.print("Following activities are selected : n");
      
    // The first activity always gets selected
    i = 0;
    System.out.print(i+" ");
      
    // Consider rest of the activities
    for (j = 1; j < n; j++)
    {
         // If this activity has start time greater than or
         // equal to the finish time of previously selected
         // activity, then select it
         if (s[j] >= f[i])
         {
              System.out.print(j+" ");
              i = j;
          }
     }
    }
      
    // driver program to test above function
    public static void main(String[] args)
    {
    int s[] =  {1, 3, 0, 5, 8, 5};
    int f[] =  {2, 4, 6, 7, 9, 9};
    int n = s.length;
        
    printMaxActivities(s, f, n);
    }
     
}


C#
// The following implementation assumes
// that the activities are already sorted
// according to their finish time
using System;
 
class GFG
{
// Prints a maximum set of activities
// that can be done by a single
// person, one at a time.
// n --> Total number of activities
// s[] --> An array that contains start
//         time of all activities
// f[] --> An array that contains finish
//         time of all activities
public static void printMaxActivities(int[] s,
                                      int[] f, int n)
{
int i, j;
 
Console.Write("Following activities are selected : ");
 
// The first activity always gets selected
i = 0;
Console.Write(i + " ");
 
// Consider rest of the activities
for (j = 1; j < n; j++)
{
    // If this activity has start time greater than or
    // equal to the finish time of previously selected
    // activity, then select it
    if (s[j] >= f[i])
    {
        Console.Write(j + " ");
        i = j;
    }
}
}
 
// Driver Code
public static void Main()
{
    int[] s = {1, 3, 0, 5, 8, 5};
    int[] f = {2, 4, 6, 7, 9, 9};
    int n = s.Length;
         
    printMaxActivities(s, f, n);
}
}
 
// This code is contributed
// by ChitraNayal


Python
"""The following implementation assumes that the activities
are already sorted according to their finish time"""
 
"""Prints a maximum set of activities that can be done by a
single person, one at a time"""
# n --> Total number of activities
# s[]--> An array that contains start time of all activities
# f[] --> An array that contains finish time of all activities
 
def printMaxActivities(s , f ):
    n = len(f)
    print "The following activities are selected"
 
    # The first activity is always selected
    i = 0
    print i,
 
    # Consider rest of the activities
    for j in xrange(n):
 
        # If this activity has start time greater than
        # or equal to the finish time of previously
        # selected activity, then select it
        if s[j] >= f[i]:
            print j,
            i = j
 
# Driver program to test above function
s = [1 , 3 , 0 , 5 , 8 , 5]
f = [2 , 4 , 6 , 7 , 9 , 9]
printMaxActivities(s , f)
 
# This code is contributed by Nikhil Kumar Singh


PHP
 Total number of activities
// s[] --> An array that contains start
//         time of all activities
// f[] --> An array that contains finish
//         time of all activities
function printMaxActivities($s, $f, $n)
{
 
    echo "Following activities are selected " . "\n";
 
    // The first activity always gets selected
    $i = 0;
    echo $i . " ";
 
    // Consider rest of the activities
    for ($j = 1; $j < $n; $j++)
    {
         
    // If this activity has start time greater
    // than or equal to the finish time of
    // previously selected activity, then select it
    if ($s[$j] >= $f[$i])
    {
        echo $j . " ";
        $i = $j;
    }
    }
}
 
// Driver Code
$s = array(1, 3, 0, 5, 8, 5);
$f = array(2, 4, 6, 7, 9, 9);
$n = sizeof($s);
printMaxActivities($s, $f, $n);
 
// This code is contributed
// by Akanksha Rai
?>


Javascript


C++
// C++ program for activity selection problem
// when input activities may not be sorted.
#include 
using namespace std;
 
// A job has a start time, finish time and profit.
struct Activitiy
{
    int start, finish;
};
 
// A utility function that is used for sorting
// activities according to finish time
bool activityCompare(Activitiy s1, Activitiy s2)
{
    return (s1.finish < s2.finish);
}
 
// Returns count of the maximum set of activities that can
// be done by a single person, one at a time.
void printMaxActivities(Activitiy arr[], int n)
{
    // Sort jobs according to finish time
    sort(arr, arr+n, activityCompare);
 
    cout << "Following activities are selected n";
 
    // The first activity always gets selected
    int i = 0;
    cout << "(" << arr[i].start << ", " << arr[i].finish << "), ";
 
    // Consider rest of the activities
    for (int j = 1; j < n; j++)
    {
      // If this activity has start time greater than or
      // equal to the finish time of previously selected
      // activity, then select it
      if (arr[j].start >= arr[i].finish)
      {
          cout << "(" << arr[j].start << ", "
              << arr[j].finish << "), ";
          i = j;
      }
    }
}
 
// Driver program
int main()
{
    Activitiy arr[] = {{5, 9}, {1, 2}, {3, 4}, {0, 6},
                                       {5, 7}, {8, 9}};
    int n = sizeof(arr)/sizeof(arr[0]);
    printMaxActivities(arr, n);
    return 0;
}


Java
// Java program for activity selection problem
// when input activities may not be sorted.
import java.io.*;
import java.util.*;
 
// A job has a start time, finish time and profit.
class Activity
{
  int start, finish;
 
  // Constructor
  public Activity(int start, int finish)
  {
    this.start = start;
    this.finish = finish;
  }
}
 
// class to define user defined comparator
class Compare
{
 
  // A utility function that is used for sorting
  // activities according to finish time
  static void compare(Activity arr[], int n)
  {
    Arrays.sort(arr, new Comparator()
                {
                  @Override
                  public int compare(Activity s1, Activity s2)
                  {
                    return s1.finish - s2.finish;
                  }
                });
  }
}
 
// Driver class
class GFG {
 
  // Returns count of the maximum set of activities that
  // can
  // be done by a single person, one at a time.
  static void printMaxActivities(Activity arr[], int n)
  {
    // Sort jobs according to finish time
    Compare obj = new Compare();
    obj.compare(arr, n);
    System.out.println(
      "Following activities are selected :");
 
    // The first activity always gets selected
    int i = 0;
    System.out.print("(" + arr[i].start + ", "
                     + arr[i].finish + "), ");
 
    // Consider rest of the activities
    for (int j = 1; j < n; j++)
    {
 
      // If this activity has start time greater than
      // or equal to the finish time of previously
      // selected activity, then select it
      if (arr[j].start >= arr[i].finish)
      {
        System.out.print("(" + arr[j].start + ", "
                         + arr[j].finish + "), ");
        i = j;
      }
    }
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    int n = 6;
    Activity arr[] = new Activity[n];
    arr[0] = new Activity(5, 9);
    arr[1] = new Activity(1, 2);
    arr[2] = new Activity(3, 4);
    arr[3] = new Activity(0, 6);
    arr[4] = new Activity(5, 7);
    arr[5] = new Activity(8, 9);
 
    printMaxActivities(arr, n);
  }
}
 
// This code is contributed by Dharanendra L V.


Python3
''' Python program for activity selection problem
 when input activities may not be sorted.'''
def MaxActivities(arr, n):
    selected = []
     
    # Sort jobs according to finish time
    Activity.sort(key = lambda x : x[1])
     
    # The first activity always gets selected
    i = 0
    selected.append(arr[i])
 
    for j in range(1, n):
       
      '''If this activity has start time greater than or
         equal to the finish time of previously selected
         activity, then select it'''
      if arr[j][0] >= arr[i][1]:
          selected.append(arr[j])
          i = j
    return selected
 
# Driver code
Activity = [[5, 9], [1, 2], [3, 4], [0, 6],[5, 7], [8, 9]]
n = len(Activity)
selected = MaxActivities(Activity, n)
print("Following activities are selected :")
print(selected)
 
# This cde is contributed by kshitijjainm


Javascript


CPP
// C++ program for activity selection problem
// when input activities may not be sorted.
#include 
using namespace std;
 
void SelectActivities(vectors,vectorf){
// Vector to store results.
    vector>ans;
 
// Minimum Priority Queue to sort activities in ascending order of finishing time (f[i]).
 
    priority_queue,vector>,greater>>p;
 
    for(int i=0;i= end){
            start = itr.second;
            end = itr.first;
            ans.push_back(make_pair(start,end));
        }
    }
    cout << "Following Activities should be selected. " << endl << endl;
 
    for(auto itr=ans.begin();itr!=ans.end();itr++){
        cout << "Activity started at: " << (*itr).first << " and ends at  " << (*itr).second << endl;
    }
}
 
// Driver program
int main()
{
    vectors = {1, 3, 0, 5, 8, 5};
    vectorf = {2, 4, 6, 7, 9, 9};
    SelectActivities(s,f);
 
    return 0;
}


Java
// java program for the above approach
import java.io.*;
import java.lang.*;
import java.util.*;
 
class GFG {
 
  // Pair class
  static class Pair {
 
    int first;
    int second;
 
    Pair(int first, int second)
    {
      this.first = first;
      this.second = second;
    }
  }
 
  static void SelectActivities(int s[], int f[])
  {
 
    // Vector to store results.
    ArrayList ans = new ArrayList<>();
 
    // Minimum Priority Queue to sort activities in
    // ascending order of finishing time (f[i]).
    PriorityQueue p = new PriorityQueue<>(
      (p1, p2) -> p1.first - p2.first);
 
    for (int i = 0; i < s.length; i++) {
      // Pushing elements in priority queue where the
      // key is f[i]
      p.add(new Pair(f[i], s[i]));
    }
 
    Pair it = p.poll();
    int start = it.second;
    int end = it.first;
    ans.add(new Pair(start, end));
 
    while (!p.isEmpty()) {
      Pair itr = p.poll();
      if (itr.second >= end) {
        start = itr.second;
        end = itr.first;
        ans.add(new Pair(start, end));
      }
    }
    System.out.println(
      "Following Activities should be selected. \n");
 
    for (Pair itr : ans) {
      System.out.println(
        "Activity started at: " + itr.first
        + " and ends at  " + itr.second);
    }
  }
 
  // Driver Code
  public static void main(String[] args)
  {
 
    int s[] = { 1, 3, 0, 5, 8, 5 };
    int f[] = { 2, 4, 6, 7, 9, 9 };
 
    // Function call
    SelectActivities(s, f);
  }
}
 
// This code is contributed by Kingash.


Javascript


输出
Following activities are selected n0 1 3 4 

对于根据完成时间排序的活动,贪婪选择如何工作?
让给定的一组活动为 S = {1, 2, 3, …n} 并且活动按完成时间排序。贪婪的选择是总是选择活动 1。为什么活动 1 总是提供最佳解决方案之一。我们可以通过证明如果有另一个解决方案 B 的第一个活动不是 1,那么还有一个与第一个活动的活动 1 大小相同的解决方案 A。设 B 选择的第一个活动为 k,则始终存在 A = {B – {k}} U {1}。

(注意 B 中的活动是独立的,k 的完成时间最短。由于 k 不是 1,finish(k) >= finish(1))。

当给定的活动没有排序时如何实施?
我们为活动创建一个结构/类。我们按完成时间对所有活动进行排序(请参阅 C++ STL 中的排序)。一旦我们对活动进行了排序,我们就会应用相同的算法。
下图是上述方法的说明:

下面是上述方法的实现:

C++

// C++ program for activity selection problem
// when input activities may not be sorted.
#include 
using namespace std;
 
// A job has a start time, finish time and profit.
struct Activitiy
{
    int start, finish;
};
 
// A utility function that is used for sorting
// activities according to finish time
bool activityCompare(Activitiy s1, Activitiy s2)
{
    return (s1.finish < s2.finish);
}
 
// Returns count of the maximum set of activities that can
// be done by a single person, one at a time.
void printMaxActivities(Activitiy arr[], int n)
{
    // Sort jobs according to finish time
    sort(arr, arr+n, activityCompare);
 
    cout << "Following activities are selected n";
 
    // The first activity always gets selected
    int i = 0;
    cout << "(" << arr[i].start << ", " << arr[i].finish << "), ";
 
    // Consider rest of the activities
    for (int j = 1; j < n; j++)
    {
      // If this activity has start time greater than or
      // equal to the finish time of previously selected
      // activity, then select it
      if (arr[j].start >= arr[i].finish)
      {
          cout << "(" << arr[j].start << ", "
              << arr[j].finish << "), ";
          i = j;
      }
    }
}
 
// Driver program
int main()
{
    Activitiy arr[] = {{5, 9}, {1, 2}, {3, 4}, {0, 6},
                                       {5, 7}, {8, 9}};
    int n = sizeof(arr)/sizeof(arr[0]);
    printMaxActivities(arr, n);
    return 0;
}

Java

// Java program for activity selection problem
// when input activities may not be sorted.
import java.io.*;
import java.util.*;
 
// A job has a start time, finish time and profit.
class Activity
{
  int start, finish;
 
  // Constructor
  public Activity(int start, int finish)
  {
    this.start = start;
    this.finish = finish;
  }
}
 
// class to define user defined comparator
class Compare
{
 
  // A utility function that is used for sorting
  // activities according to finish time
  static void compare(Activity arr[], int n)
  {
    Arrays.sort(arr, new Comparator()
                {
                  @Override
                  public int compare(Activity s1, Activity s2)
                  {
                    return s1.finish - s2.finish;
                  }
                });
  }
}
 
// Driver class
class GFG {
 
  // Returns count of the maximum set of activities that
  // can
  // be done by a single person, one at a time.
  static void printMaxActivities(Activity arr[], int n)
  {
    // Sort jobs according to finish time
    Compare obj = new Compare();
    obj.compare(arr, n);
    System.out.println(
      "Following activities are selected :");
 
    // The first activity always gets selected
    int i = 0;
    System.out.print("(" + arr[i].start + ", "
                     + arr[i].finish + "), ");
 
    // Consider rest of the activities
    for (int j = 1; j < n; j++)
    {
 
      // If this activity has start time greater than
      // or equal to the finish time of previously
      // selected activity, then select it
      if (arr[j].start >= arr[i].finish)
      {
        System.out.print("(" + arr[j].start + ", "
                         + arr[j].finish + "), ");
        i = j;
      }
    }
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    int n = 6;
    Activity arr[] = new Activity[n];
    arr[0] = new Activity(5, 9);
    arr[1] = new Activity(1, 2);
    arr[2] = new Activity(3, 4);
    arr[3] = new Activity(0, 6);
    arr[4] = new Activity(5, 7);
    arr[5] = new Activity(8, 9);
 
    printMaxActivities(arr, n);
  }
}
 
// This code is contributed by Dharanendra L V.

蟒蛇3

''' Python program for activity selection problem
 when input activities may not be sorted.'''
def MaxActivities(arr, n):
    selected = []
     
    # Sort jobs according to finish time
    Activity.sort(key = lambda x : x[1])
     
    # The first activity always gets selected
    i = 0
    selected.append(arr[i])
 
    for j in range(1, n):
       
      '''If this activity has start time greater than or
         equal to the finish time of previously selected
         activity, then select it'''
      if arr[j][0] >= arr[i][1]:
          selected.append(arr[j])
          i = j
    return selected
 
# Driver code
Activity = [[5, 9], [1, 2], [3, 4], [0, 6],[5, 7], [8, 9]]
n = len(Activity)
selected = MaxActivities(Activity, n)
print("Following activities are selected :")
print(selected)
 
# This cde is contributed by kshitijjainm

Javascript


输出:

Following activities are selected 
(1, 2), (3, 4), (5, 7), (8, 9),

时间复杂度:如果输入的活动无法排序,则需要 O(n log n) 时间。当给定输入活动总是排序时,需要 O(n) 时间。
使用STL我们可以解决它如下:

CPP

// C++ program for activity selection problem
// when input activities may not be sorted.
#include 
using namespace std;
 
void SelectActivities(vectors,vectorf){
// Vector to store results.
    vector>ans;
 
// Minimum Priority Queue to sort activities in ascending order of finishing time (f[i]).
 
    priority_queue,vector>,greater>>p;
 
    for(int i=0;i= end){
            start = itr.second;
            end = itr.first;
            ans.push_back(make_pair(start,end));
        }
    }
    cout << "Following Activities should be selected. " << endl << endl;
 
    for(auto itr=ans.begin();itr!=ans.end();itr++){
        cout << "Activity started at: " << (*itr).first << " and ends at  " << (*itr).second << endl;
    }
}
 
// Driver program
int main()
{
    vectors = {1, 3, 0, 5, 8, 5};
    vectorf = {2, 4, 6, 7, 9, 9};
    SelectActivities(s,f);
 
    return 0;
}

Java

// java program for the above approach
import java.io.*;
import java.lang.*;
import java.util.*;
 
class GFG {
 
  // Pair class
  static class Pair {
 
    int first;
    int second;
 
    Pair(int first, int second)
    {
      this.first = first;
      this.second = second;
    }
  }
 
  static void SelectActivities(int s[], int f[])
  {
 
    // Vector to store results.
    ArrayList ans = new ArrayList<>();
 
    // Minimum Priority Queue to sort activities in
    // ascending order of finishing time (f[i]).
    PriorityQueue p = new PriorityQueue<>(
      (p1, p2) -> p1.first - p2.first);
 
    for (int i = 0; i < s.length; i++) {
      // Pushing elements in priority queue where the
      // key is f[i]
      p.add(new Pair(f[i], s[i]));
    }
 
    Pair it = p.poll();
    int start = it.second;
    int end = it.first;
    ans.add(new Pair(start, end));
 
    while (!p.isEmpty()) {
      Pair itr = p.poll();
      if (itr.second >= end) {
        start = itr.second;
        end = itr.first;
        ans.add(new Pair(start, end));
      }
    }
    System.out.println(
      "Following Activities should be selected. \n");
 
    for (Pair itr : ans) {
      System.out.println(
        "Activity started at: " + itr.first
        + " and ends at  " + itr.second);
    }
  }
 
  // Driver Code
  public static void main(String[] args)
  {
 
    int s[] = { 1, 3, 0, 5, 8, 5 };
    int f[] = { 2, 4, 6, 7, 9, 9 };
 
    // Function call
    SelectActivities(s, f);
  }
}
 
// This code is contributed by Kingash.

Javascript


输出
Following Activities should be selected. 

Activity started at: 1 and ends at  2
Activity started at: 3 and ends at  4
Activity started at: 5 and ends at  7
Activity started at: 8 and ends at  9

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程