You have a problem where you need to find the minimum number of coins to make a certain amount using given coin denominations. Which approach is best and why?
Think about whether a local choice leads to a global optimum.
Greedy works when the problem has the greedy-choice property, such as canonical coin systems. Otherwise, DP is needed to explore all combinations.
What is the output of the following C++ code that selects maximum activities using Greedy and DP?
#include <iostream> #include <vector> #include <algorithm> using namespace std; struct Activity { int start, finish; }; bool activityCompare(Activity s1, Activity s2) { return (s1.finish < s2.finish); } int greedyActivitySelector(vector<Activity> &activities) { sort(activities.begin(), activities.end(), activityCompare); int count = 1; int last_finish = activities[0].finish; for (int i = 1; i < activities.size(); i++) { if (activities[i].start >= last_finish) { count++; last_finish = activities[i].finish; } } return count; } int main() { vector<Activity> activities = {{1,4}, {3,5}, {0,6}, {5,7}, {8,9}, {5,9}}; cout << greedyActivitySelector(activities) << endl; return 0; }
Count how many activities can be selected without overlapping using earliest finish time.
The greedy approach selects activities by earliest finish time, allowing 4 activities to be selected.
Consider this DP code for 0/1 Knapsack. It returns wrong maximum value. What is the bug?
#include <iostream> #include <vector> using namespace std; int knapsack(int W, vector<int> &wt, vector<int> &val, int n) { vector<vector<int>> dp(n+1, vector<int>(W+1, 0)); for (int i = 1; i <= n; i++) { for (int w = 1; w <= W; w++) { if (wt[i-1] <= w) { dp[i][w] = max(val[i-1] + dp[i-1][w - wt[i-1]], dp[i-1][w]); } else { dp[i][w] = dp[i-1][w]; } } } return dp[n][W]; } int main() { vector<int> wt = {1, 3, 4, 5}; vector<int> val = {1, 4, 5, 7}; int W = 7; cout << knapsack(W, wt, val, wt.size()) << endl; return 0; }
Check how arrays wt and val are accessed inside the loops.
Arrays wt and val are zero-indexed but code accesses wt[i], val[i] starting from i=1, causing wrong values or out-of-range access.
What is the output of this C++ code that compares greedy and DP solutions for coin change amount 6 with coins {1,3,4}?
#include <iostream> #include <vector> #include <algorithm> using namespace std; int greedyCoinChange(vector<int> &coins, int amount) { sort(coins.rbegin(), coins.rend()); int count = 0; for (int coin : coins) { while (amount >= coin) { amount -= coin; count++; } } if (amount != 0) return -1; return count; } int dpCoinChange(vector<int> &coins, int amount) { vector<int> dp(amount+1, amount+1); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int coin : coins) { if (coin <= i) { dp[i] = min(dp[i], dp[i - coin] + 1); } } } return dp[amount] > amount ? -1 : dp[amount]; } int main() { vector<int> coins = {1, 3, 4}; int amount = 6; cout << greedyCoinChange(coins, amount) << " " << dpCoinChange(coins, amount) << endl; return 0; }
Trace greedy picking largest coins first and DP finding minimum coins.
Greedy picks 4+1+1=3 coins but code counts 6 coins because it subtracts 1 repeatedly after 4. DP finds minimum 2 coins (3+3).
Which property of a problem ensures that a greedy algorithm will always produce an optimal solution, making dynamic programming unnecessary?
Think about what makes a local choice lead to a global optimum.
Greedy algorithms require the greedy-choice property (local optimal choices lead to global optimum) and optimal substructure (optimal solution contains optimal subsolutions).
