Knapsack problem with multiple availabe packages using dynamic programming - c++

Hello and thanks for helping!
So we've got a list of fireworks containing 1) Number in stock 2) Number of fireworks in this package 3) Diameter which equals the noise and
4) The price.
This is the list:
25 17 10 21
10 15 10 18
5 16 10 19
10 15 12 20
15 9 11 12
10 7 28 23
8 7 16 11
10 6 16 10
25 10 18 25
25 12 18 27
10 5 40 35
60 40 5 27
5 25 30 90
50 1 60 8
Our task is to create a shopping list and buy fireworks so we get the highest possible noise. We've got a knapsack capacity of 1000€. We're also supposed to solve this without using tables (so with dynamic programming instead).
I only use one class called Package which contains the four constraints as shown above.
At first I thought it would make sense to try to write an algorithm for a normal knapsack, so just with the price and the diameter (=weight). I tested it with a different list and it worked perfectly fine. I just iterated through all packages and then again used a nested for loop to find the best constellation (exhaustive search). My next idea was to merge the number of fireworks per package with the diameter, because fireworks can only be bought in a full package.
The only thing left which I still haven't found out is what to do with the amount of packages in stock. Like, with my current algorithm it just buys all packages of a firework until the knapsack is full. But obviously that won't be correct.
void knapsack(vector<Package*> stock){
vector<int> indices, tmp_indices;
int noise,tmp_noise= 0;
int price;
for (unsigned int i = 0; i < stock.size(); i++) {
price = stock[i]->price;
noise = stock[i]->diameter*stock[i]->number_fireworks;
indices.push_back(i);
for (unsigned int j = 0; j < stock.size(); j++) {
if (i != j) {
if (price+stock[j]->price<= BUDGET) {
price+=stock[j]->price;
noise+=stock[j]->diameter*stock[j]->number_fireworks;
indices.push_back(j);
}
}
}
// After second loop we have a new possible constellation
// Check if the previous constellation had a lower value and if so, set it to the current one
if (noise > tmp_noise) {
tmp_noise = noise;
tmp_indices.clear();
// tmp save
for (auto &index : indices) {
tmp_indices.push_back(index);
}
}
price= 0;
noise = 0;
indices.clear();
}
// Best constellation found, Print the shopping list
cout << "\Stock.\tNum\Diameter.\Price\n" << endl;
for(unsigned int i = 0; i < tmp_indices.size(); i++) {
cout << stock[tmp_indices[i]]->stock<< "\t";
cout << stock[tmp_indices[i]]->number_fireworks<< "\t";
cout << stock[tmp_indices[i]]->diameter<< "\t";
cout << stock[tmp_indices[i]]->price<< "\t\n";
}
}
We've been told that we should be able to spend exactly 1000€ to get the correct constellation of fireworks. My idea was to add another for loop to iterate through the amount of available packages, but that didn't really work...
This was our first lesson and I'm a bit desperate, because we have only learned how to solve a knapsack problem with 2 constraints and by using a table R.
Edit: Since one user insisted to get a specific question, here it is: Is the idea of using another loop to include the third constraint correct or is there a better/easier way of doing it? Or is it possible that I need a completely different approach for a knapsack with 3 instead of 2 constraints?
Thanks for help in advance

Related

How to iterate two vectors in one for loop?

I'm only showing my functions because I believe the problem is in my for loop.
DataStoreVectors::DataStoreVectors() {
}
void DataStoreVectors::addItem(string item1, int item2) {
videoGame.push_back(item1);
gameSize.push_back(item2);
}
void DataStoreVectors::listItems()
{
vector <string>::iterator pv;
vector <int>::iterator px;
for (pv = videoGame.begin(); pv < videoGame.end(); pv++)
{
for (px = gameSize.begin(); px < gameSize.end(); px++)
cout << *pv << " " << *px << endl;
}
}
When I try to print out the data in my two arrays, it prints out the name of each video game about 6 times and assigns my int values to them like so:
Valorant 8
Valorant 70
Valorant 50
Valorant 1
Valorant 26
Valorant 35
Fortnite 8
Fortnite 70
Fortnite 50
Fortnite 1
Fortnite 26
Fortnite 35
Doom Eternal 8
Doom Eternal 70
Doom Eternal 50
Doom Eternal 1
Doom Eternal 26
Doom Eternal 35
Minecraft 8
Minecraft 70
Minecraft 50
Minecraft 1
Minecraft 26
Minecraft 35
Apex Legends 8
Apex Legends 70
Apex Legends 50
Apex Legends 1
Apex Legends 26
Apex Legends 35
Control 8
Control 70
Control 50
Control 1
Control 26
Control 35
Is this possible? Would it be better to make a struct? I'm trying to figure out the right way to print out two vectors side by side.
It's quite simple to keep the iterators synchronized in position. Just add another increment in the for loop like this:
vector <int>::iterator px = gameSize.begin(); // << Add this
for (pv = videoGame.begin(); pv < videoGame.end(); pv++, px++)
// ^^^^^^ Add this
Ensure that both vectors have the same size, or the vector px points to is at least bigger than the other one (videoGame) though.
You could use a range-v3 zip view.
for (auto [game, size] : ranges::views::zip(videoGame, gameSize))
{
std::cout << game << " " << size << std::endl;
}
If the data is linked then you should make a struct from this.
I also recommend giving your parameters a more descriptive name in addItem such as addItem(string gameName, int gameSize) and maybe rename the vectors to use the plural form such as videoGames and gameSizes.
Regarding the iteration over two vectors you can iterate over those with a simple int index (this assumes both vectors have the same size as it seems to be in your case):
for (int i = 0; i < videoGame.size(); ++i)
{
cout << videoGame[i] << " " << gameSize[i] << endl;
}
You can increment each iterator in the same loop, but both arrays would need to be the same size, however it's a horrible bug prone approach, your single array of a struct that includes both fields is a far better approach.

Trying to find root mean square of two rows in array

i am working through an EDX course on computer programming. I have come to this problem and dont know how to work through it. im not looking for an answer but more a point in the right direction.
so the question gives you a 2D array. two columns and N amount of rows. the N is the number of students. each column is the grade of first test and then the second is the grade of the second test. I am asked to find the root mean square of two seperate kids and compare them and then return a number based off the comparison. The question gives you this formula
RMS = (0.5×(midsem_marks2 + endsem_marks2))0.5
I know how to get the appropriate marks using array[index 1(firsttest)] etc and then how to compare them. However, i am clueless on how to write that formula. any help would be great. Thanks in advance.
code I have
float RMSi1 = sqrt(.5*((marksarray[index1][0]*marksarray[index1][0])+(marksarray[index1][1])*(marksarray[index1][1])));
float RMSi2 = sqrt(.5*((marksarray[index2][0]*marksarray[index2][0])+(marksarray[index2][1])*(marksarray[index2][1])));
if(RSMi1>RSMi2){
return -1;
}
if(RSMi1<RSMi2){
return 1;
}
if(RSMi1==RSMi2){
return 0;
}
I'm getting an error that the RSMi1 and 2 are not declared in the if statements
Input marksarray:
1 2
1 60 20
2 60 20
3 30 40
4 10 90
5 90 30
6 0 100
7 60 20

Need Help in a Project of C++

So this is the actual Problem
Can anyone tell me that how I read the repective Data from the file, and how would I able to store it in variables (without using array) also the code should be generic, That if the number of series will incresed or decresed.. Code will not be affected... I Just can't understand that how would I store sata in variables and how.. Please Help.. :(
Problem
A file contains information of a batsman. Information is no of series
played by the batsman. No of matches played in each series & score in
each match by the batsman. You have to read the data (without using
any array) and find average score and maximum score in all matches of
a series. In the end find overall average score and max score in all
matches.
Input:
Read data from file "cricket.txt". First line contains no of seasons/
series played by the player. Next pair of lines contains matches
played by the batsman followed in next line scores by batsman in
different matches of a season. See sample "cricket.txt"
5
6
93 75 41 40 90 19
5
45 86 30 60 29
3
47 90 33
4
22 2 92 5
5
88 67 96 91 90
First 5 shows player has played 5 seasons/ series
Next 6 show in first series player has played 6 matches
Next line has scores of player in 6 matches
Next 5 show in second series player has played 5 matches
Next line has scores of player in 5 matches
So on in second last line 5 shows player has played 5 matches in 5th
series
Last line has scores of player in 5 matches of last series
You're looking for an array.
int a[10];
// Loop that assigns all elements in array a to 0
for (int i = 0; i < 10; i++)
{
a[i] = 0;
}
// Array b will have all of it's members initialized to 0
int b[10]{};
// You can also assign different values to different elements of the array
b[0] = 6;
b[8] = 2;
// You can then use the array elements in operations
int c = b[0] * b[8];
If you want array like structure without compile time defined size, then use std::vector.
// An empty vector of ints
std::vector<int> d;
// A simple int
int e = 5;
// Push 2 values to the end of the vector
d.push_back(2);
d.push_back(e);
// Use the members for operations
int f = d.at(0) * d.at(1);
Since you've now described the problem you're trying to solve instead of just the problem with the solution you came up with:
You don't need to invent variable names or use arrays to compute averages and maximums.
Here's an example of how you can compute an average of the numbers a user inputs:
float sum = 0;
int elements = 0;
float input = 0;
while (cin >> input)
{
sum += input;
elements += 1;
}
std::cout << "Average: " << sum / elements << std::endl;
It's easy to expand this to also keep track of the maximum value so far.
To expand to the average and maximum of a number of series, add another loop "around" it.

A program that takes in a matrix and outputs the fastest path to the "exit" and the number it takes to get there

So I'm having a lot of trouble understanding c++ again I've taken my programming class twice and failed. I need help. I'm not interested in programming anymore because it's obviously not for me. I just need to pass. Here's the problem:
The goal of this assignment is to practice recursive algorithms by writing a program that takes in a matrix representing the number of guards in each room of the castle and outputs the fastest path to the princess and the number of guards you will have to fight.
You're moving through a map(array) that looks like:
5 5
6 2 3 44 15
1 7 2 9 10
11 1 5 14 12
5 17 2 1 20
21 7 33 4 25
Where the first to numbers are the size of your array and you can only move right and down.
So an output would be:
50 > > v v v > v >
We're given a skeleton which we have to fill in but I don't know what some of it does and it might be too long to copy and paste here, I'm new to the community.
How would you tackle this assignment
Using recursion you try to simplify the problem. So take a step right, compute the score for this step and add it to the rest of the solution by calling the same function on a smaller matrix (leaving out the left column). Then take a step down and do the same with the smaller matrix leaving out the top row. Then choose the solution with the lowest score.
This is just a dynamic programming problem.
I don't know how to pass a 2-d array as a function parameter.
Someone correct me please(How to pass 'matrix' array and 'result' array as function parameters). Rest all part is fine
Algorithm is simple. Just start from the last position and come backwards.
where result[i][j] = min(result[i+1][j],result[i][j+1])
void function(int a,int b,int** matrix,int** result){
if(result[a+1][b] == -1 && result[a][b+1] == -1){
result[a][b] = min(function(a+1,b,matrix,result),function(a,b+1,matrix,result));
}
else if(result[a+1][b] == -1 && result[a][b+1] != -1){
result[a][b] = min(function(a+1,b,matrix,result),result[a][b+1]);
}
else if(result[a+1][b] != -1 && result[a][b+1] == -1){
result[a][b] = min(result[a+1][b],function(a,b+1,matrix,result));
}
return;
}
int main(){
int p,q;
cin>>p>>q;
int matrix[p][q];
for(int i=0;i<p;i++){
for(int j=0;j<q;j++){
cin>>matrix[i][j];
}
}
int result[p][q];
for(int i=0;i<p;i++){
for(int j=0;j<q;j++){
result[i][j] = -1;
}
}
result[p-1][q-1] = matrix[p-1][q-1];
for(int i=q-2;i>=0;i++){
result[p-1][i] = matrix[p-1][i] + result[p-1][i+1];
}
for(int i=p-2;i>=0;i++){
result[i][q-1] = matrix[i][q-1] + result[i+1][q-1];
}
function(0,0,matrix,result);
cout<<results[0][0]<<endl;
}

Greedy algorithm error using c++ sets

I've created a greedy algorithm to solve a problem (homework assignment) and since I'm learning c++ I would like to achieve the same thing but using sets.
Basically we submit the homework to an online platform, this platform as some test cases that we don't know of, and we get a score based on that. If we pass all test cases we have 100%;
The problem is like this.
We have an actor that wants to schedule appointments with the fans that answered an online questionnaire about him. Now he wants to choose the fan's that maximizes the sum of points in the questionnaire and respecting the fan's availability. He can see only one fan a day.
We have an input like this:
6
1 1 5
2 2 4
3 1 2
4 3 1
5 1 6
6 2 2
Where the first line is the number of fans and following, in each line, we have the fan id, the fan available days and the fan points achieved in the online questionnaire. I must print the ids of the fans that the actor will see and the sum of combined points of the fans. So for the above input I have the following output:
2
4
5
11
Note that if two fans have the same points, the fan prefered should be the one with the lower ID.
I've started by sorting the fans by the points of the questionnaire (decreasing order) and then by the lower id.
When reading the input, I'm adding the number of days to a set.
My idea was like this:
When iterating over the data, I check if the fan in study days available is in the set. If it is, add this fan and remove the days from the set. If the fan days is not in the set, then get the upper_bound and decrease the iterator to set the fan on the first day lower that the initial day. The algorithm stops wen the set is empty or I iterate all over the fans.
Here is my greedy function:
void greedy() {
fan_id.insert(questionnaire_result[0][0]);
days_available.erase(questionnaire_result[0][1]);
total_questionaire_sum += questionnaire_result[0][2];
int i;
for (i = 1; i < number_of_fans; i++) {
if (days_available.empty()) {
break;
} else if (days_available.count(questionnaire_result[i][1])) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(questionnaire_result[i][1]);
total_questionaire_sum += questionnaire_result[i][2];
} else {
it = days_available.upper_bound(questionnaire_result[i][1]);
if (it == days_available.begin()) {
if (*it < questionnaire_result[i][1]) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(*it);
total_questionaire_sum += questionnaire_result[i][2];
}
} else if (it == days_available.end()) {
it--;
if (*it < questionnaire_result[i][1]) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(*it);
total_questionaire_sum += questionnaire_result[i][2];
}
} else {
it--;
if (*it < questionnaire_result[i][1]) {
fan_id.insert(questionnaire_result[i][0]);
days_available.erase(*it);
total_questionaire_sum += questionnaire_result[i][2];
}
}
}
}
}
I believe my problem is in this line:
it = days_available.upper_bound(questionnaire_result[i][1]);
I've tested many possibilities and this is working in all my test cases. Unfortunately, we don't have the test cases of the platform.
Does someone see an situation that my code fails? With this I'm getting 90% of the score.
EDIT:
As Edward pointed me out, I've managed to solve the problem like this:
When reading the input added this line of code:
max_days = max_days | questionnaire_result[i][1];
And then did this:
for (int j = 1; j < max_days + 1; j++) {
days_available.insert(j);
}
Problem solved
This input file will cause the program to generate an incorrect result:
2
1 2 6
2 2 5
Both fans are available either day, so it's clear that both fans could be visited and the total output score should be 11. Your algorithm, however, only chooses the first one and outputs a score of 6.