mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-04-15 02:07:36 +00:00
Create-Add files to greedy_method directory (#2082)
* Add Greedy Method Approach * Update Filename * Update Variable and Links * Fixed flake8 bugs * Update unittest filename * Update unittest filename * Final unittest filename update * Pythonic Code formatting * flake8 fixes * lowercase function name * Add zip function * Add zip function * params lowercase * Travis CI fixes * Update and rename knapsack_problem.py to knapsack.py * Update test_knapsack.py * Fix bugs * Rename knapsack.py to greedy_knapsack.py * Update test_knapsack.py Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
parent
1e7df7f77a
commit
7be3d0f667
99
greedy_method/greedy_knapsack.py
Normal file
99
greedy_method/greedy_knapsack.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# To get an insight into Greedy Algorithm through the Knapsack problem
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
A shopkeeper has bags of wheat that each have different weights and different profits.
|
||||||
|
eg.
|
||||||
|
profit 5 8 7 1 12 3 4
|
||||||
|
weight 2 7 1 6 4 2 5
|
||||||
|
max_weight 100
|
||||||
|
|
||||||
|
Constraints:
|
||||||
|
max_weight > 0
|
||||||
|
profit[i] >= 0
|
||||||
|
weight[i] >= 0
|
||||||
|
Calculate the maximum profit that the shopkeeper can make given maxmum weight that can
|
||||||
|
be carried.
|
||||||
|
"""
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
def calc_profit(profit: list, weight: list, max_weight: int) -> Union[str, int]:
|
||||||
|
"""
|
||||||
|
Function description is as follows-
|
||||||
|
:param profit: Take a list of profits
|
||||||
|
:param weight: Take a list of weight if bags corresponding to the profits
|
||||||
|
:param max_weight: Maximum weight that could be carried
|
||||||
|
:return: Maximum expected gain
|
||||||
|
|
||||||
|
>>> calc_profit([1, 2, 3], [3, 4, 5], 15)
|
||||||
|
6
|
||||||
|
>>> calc_profit([10, 9 , 8], [3 ,4 , 5], 25)
|
||||||
|
27
|
||||||
|
"""
|
||||||
|
if len(profit) != len(weight):
|
||||||
|
raise ValueError("The length of profit and weight must be same.")
|
||||||
|
if max_weight <= 0:
|
||||||
|
raise ValueError("max_weight must greater than zero.")
|
||||||
|
if any(p < 0 for p in profit):
|
||||||
|
raise ValueError("Profit can not be negative.")
|
||||||
|
if any(w < 0 for w in weight):
|
||||||
|
raise ValueError("Weight can not be negative.")
|
||||||
|
|
||||||
|
# List created to store profit gained for the 1kg in case of each weight
|
||||||
|
# respectively. Calculate and append profit/weight for each element.
|
||||||
|
profit_by_weight = [p / w for p, w in zip(profit, weight)]
|
||||||
|
|
||||||
|
# Creating a copy of the list and sorting profit/weight in ascending order
|
||||||
|
sorted_profit_by_weight = sorted(profit_by_weight)
|
||||||
|
|
||||||
|
# declaring useful variables
|
||||||
|
length = len(sorted_profit_by_weight)
|
||||||
|
limit = 0
|
||||||
|
gain = 0
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
# loop till the total weight do not reach max limit e.g. 15 kg and till i<length
|
||||||
|
while limit <= max_weight and i < length:
|
||||||
|
# flag value for encountered greatest element in sorted_profit_by_weight
|
||||||
|
biggest_profit_by_weight = sorted_profit_by_weight[length - i - 1]
|
||||||
|
"""
|
||||||
|
Calculate the index of the biggest_profit_by_weight in profit_by_weight list.
|
||||||
|
This will give the index of the first encountered element which is same as of
|
||||||
|
biggest_profit_by_weight. There may be one or more values same as that of
|
||||||
|
biggest_profit_by_weight but index always encounter the very first element
|
||||||
|
only. To curb this alter the values in profit_by_weight once they are used
|
||||||
|
here it is done to -1 because neither profit nor weight can be in negative.
|
||||||
|
"""
|
||||||
|
index = profit_by_weight.index(biggest_profit_by_weight)
|
||||||
|
profit_by_weight[index] = -1
|
||||||
|
|
||||||
|
# check if the weight encountered is less than the total weight
|
||||||
|
# encountered before.
|
||||||
|
if max_weight - limit >= weight[index]:
|
||||||
|
limit += weight[index]
|
||||||
|
# Adding profit gained for the given weight 1 ===
|
||||||
|
# weight[index]/weight[index]
|
||||||
|
gain += 1 * profit[index]
|
||||||
|
else:
|
||||||
|
# Since the weight encountered is greater than limit, therefore take the
|
||||||
|
# required number of remaining kgs and calculate profit for it.
|
||||||
|
# weight remaining / weight[index]
|
||||||
|
gain += (max_weight - limit) / weight[index] * profit[index]
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
return gain
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(
|
||||||
|
"Input profits, weights, and then max_weight (all positive ints) separated by "
|
||||||
|
"spaces."
|
||||||
|
)
|
||||||
|
|
||||||
|
profit = [int(x) for x in input("Input profits separated by spaces: ").split()]
|
||||||
|
weight = [int(x) for x in input("Input weights separated by spaces: ").split()]
|
||||||
|
max_weight = int(input("Max weight allowed: "))
|
||||||
|
|
||||||
|
# Function Call
|
||||||
|
calc_profit(profit, weight, max_weight)
|
74
greedy_method/test_knapsack.py
Normal file
74
greedy_method/test_knapsack.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import unittest
|
||||||
|
import greedy_knapsack as kp
|
||||||
|
|
||||||
|
|
||||||
|
class TestClass(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Test cases for knapsack
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_sorted(self):
|
||||||
|
"""
|
||||||
|
kp.calc_profit takes the required argument (profit, weight, max_weight)
|
||||||
|
and returns whether the answer matches to the expected ones
|
||||||
|
"""
|
||||||
|
profit = [10, 20, 30, 40, 50, 60]
|
||||||
|
weight = [2, 4, 6, 8, 10, 12]
|
||||||
|
max_weight = 100
|
||||||
|
self.assertEqual(kp.calc_profit(profit, weight, max_weight), 210)
|
||||||
|
|
||||||
|
def test_negative_max_weight(self):
|
||||||
|
"""
|
||||||
|
Returns ValueError for any negative max_weight value
|
||||||
|
:return: ValueError
|
||||||
|
"""
|
||||||
|
# profit = [10, 20, 30, 40, 50, 60]
|
||||||
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
|
# max_weight = -15
|
||||||
|
self.assertRaisesRegex(ValueError, "max_weight must greater than zero.")
|
||||||
|
|
||||||
|
def test_negative_profit_value(self):
|
||||||
|
"""
|
||||||
|
Returns ValueError for any negative profit value in the list
|
||||||
|
:return: ValueError
|
||||||
|
"""
|
||||||
|
# profit = [10, -20, 30, 40, 50, 60]
|
||||||
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
|
# max_weight = 15
|
||||||
|
self.assertRaisesRegex(
|
||||||
|
ValueError, "Weight can not be negative.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_negative_weight_value(self):
|
||||||
|
"""
|
||||||
|
Returns ValueError for any negative weight value in the list
|
||||||
|
:return: ValueError
|
||||||
|
"""
|
||||||
|
# profit = [10, 20, 30, 40, 50, 60]
|
||||||
|
# weight = [2, -4, 6, -8, 10, 12]
|
||||||
|
# max_weight = 15
|
||||||
|
self.assertRaisesRegex(ValueError, "Profit can not be negative.")
|
||||||
|
|
||||||
|
def test_null_max_weight(self):
|
||||||
|
"""
|
||||||
|
Returns ValueError for any zero max_weight value
|
||||||
|
:return: ValueError
|
||||||
|
"""
|
||||||
|
# profit = [10, 20, 30, 40, 50, 60]
|
||||||
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
|
# max_weight = null
|
||||||
|
self.assertRaisesRegex(ValueError, "max_weight must greater than zero.")
|
||||||
|
|
||||||
|
def test_unequal_list_length(self):
|
||||||
|
"""
|
||||||
|
Returns IndexError if length of lists (profit and weight) are unequal.
|
||||||
|
:return: IndexError
|
||||||
|
"""
|
||||||
|
# profit = [10, 20, 30, 40, 50]
|
||||||
|
# weight = [2, 4, 6, 8, 10, 12]
|
||||||
|
# max_weight = 100
|
||||||
|
self.assertRaisesRegex(IndexError, "The length of profit and weight must be same.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user