The knapsack problem, visual studio issues - c++

I implemented a dynamic programming solution to the famous knapsack problem. Now the funny part of this is that visual studio will not allow my code to compile yet when I copy and paste my code in cpp.sh it runs fine with no errors.
At the moment this is what I am getting in visuial studio for errors:
Unhandled exception at 0x0FADED76 (ucrtbased.dll) in Practice.exe: An invalid
parameter was passed to a function that considers invalid parameters fatal.
This occurs at line 10, i.e. dp[i][j] = 0. I am not sure how to fix this issue, and in general I have noticed that visual studio can be particularly whiny.
Here is my code:
#include <iostream>
#include <vector>
#include <algorithm>
int maxKnapSack(std::vector<int>& v, std::vector<int>& w, int capacity) {
std::vector<std::vector<int>> dp(capacity + 1, std::vector<int>(v.size() + 1));
for (int i = 0; i <= v.size(); i++) {
for (int j = 0; j <= capacity; j++) {
if (i == 0 || j == 0) {
dp[i][j] = 0;
}
else if (j - w[i - 1] >= 0) {
dp[i][j] = std::max(v[i-1] + dp[i - 1][j - w[i-1]], dp[i - 1][j]);
}
else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[v.size()][capacity];
}
int main() {
std::vector<int> v = { 10, 4, 7 };
std::vector<int> w = { 4, 2, 3 };
int capacity = 5;
std::cout << "The maximum I can get is " << maxKnapSack(v, w, capacity) << "\n";
std::cin.get();
}

Your vector dp contains 6 elements, each element being a vector of 4 elements. It's equivalent to the array definition int dp[6][4].
Your outer loop loop from 0 to 4 (inclusive) and the inner loop loops from 0 to 6 (inclusive). That means you will use index out of bounds in the nested (inner) vector.
Your loops should be the other way around with their limits. Or your vector dp should be defined with the sizes switched.
Your conditions inside the inner loop are also wrong. The condition i == 0 || j == 0 will be false if e.g. i == 0 and j != 0. That will then lead to you using negative indexes because of i - 1. That is also out of bounds and again lead to undefined behavior.
You need to make sure that the else if only happens when i > 0 and j - w[i-1] > 0 as well. And the else only when i > 0.

Related

Heap-buffer overflow when implementing two-pointer approch

I'm solving this brain teaser
Given a 1-indexed array of integers numbers that is already sorted in
non-decreasing order, find two numbers such that they add up to a
specific target number. Let these two numbers be numbers[index1] and
numbers[index2] where 1 <= index1 < index2 <= numbers.length.
Return the indices of the two numbers, index1 and index2, added by one
as an integer array [index1, index2] of length 2.
The tests are generated such that there is exactly one solution. You
may not use the same element twice.
Your solution must use only constant extra space.
Example 1:
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9.
Therefore, index1 = 1, index2 = 2.
We return [1, 2].
and my solution is giving this error:
=================================================================
==31==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000620 at pc 0x000000345e97 bp 0x7ffcd6847990 sp 0x7ffcd6847988
READ of size 4 at 0x602000000620 thread T0
#2 0x7f2c3b9790b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x602000000620 is located 0 bytes to the right of 16-byte region [0x602000000610,0x602000000620)
I did some research and saw that this is usually caused by calling an index that's too far (i.e. outside the range of the data structure you're using) but since I'm using vectors I don't get why I have this error. It happened on the following test case: [5,25,75]
100.
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
// can have an i that points forward and a j that loops through everything until sum
// is greater
// checking recursively
// if sum greater stop checking (as list is increasing)
// can reset i each time??
// add 1 at the end
vector<int> indices;
int i = 0;
int j = 0;
// for loop on top?
for (int i; i < numbers.size(); i++)
int j = 0;
while (numbers[i] + numbers[j] <= target) {
if (numbers[i] + numbers[j] == target && i != j) {
// some if determining if i or j is greater
// to determine the order in which to push back
indices.push_back(i+1);
indices.push_back(j+1);
return indices;
} else {
j++;
}
}
return indices;
}
};
The other tests are passing but this one is failing. I am trying to use a two-pointer approach here.
There are several issues with this code, some simple syntactic mistakes, some algorithmic problems.
First, as others have mentioned, i is uninitialized in your outer for loop. Luckily, that never comes into play because you have no braces around the loop body. Your code is equivilent to
for (int i; i < numbers.size(); i++) {
int j = 0;
}
while (numbers[i] + numbers[j] <= target) {
// ...
}
This is presumably not what you intended, so you need to both initialize i and add {} around the loop body:
for (int i = 0; i < numbers.size(); i++) {
int j = 0;
while (numbers[i] + numbers[j] <= target) {
// ...
}
}
Of course, you also don't need the redundant definitions of i and j outside the loops. Those variables get hidden by the ones defined within the loops, and are never used.
Of course, this still doesn't address your out-of-range error. For that, you need to re-think your algorithm. Lets walk through it to find the issue. I'll just focus on the inner while loop.
Assuming, from your test case that numbers = {5, 25, 75} and target = 100.
First iteration:
i = 0 and j = 0
numbers[i] + numbers[j] -> numbers[0] + numbers[0] -> -> 5 + 5 -> 10. That's less than 100, so the loop is entered
if (10 == 100) is false, so the else branch is selected
j++, so now i = 0 and j = 1
Second iteration:
numbers[i] + numbers[j] -> numbers[0] + numbers[1] -> 5 + 25 -> 30. That's less than 100, so the loop continues
if (30 == 100) is false, so the else branch is selected
j++, so now i = 0 and j = 2
Third iteration:
numbers[i] + numbers[j] -> numbers[0] + numbers[2] -> 5 + 75 -> 80. That's less than 100, so the loop continues
if (80 == 100) is false, so the else branch is selected
j++, so now i = 0 and j = 3
Third iteration:
numbers[i] + numbers[j] -> numbers[0] + numbers[3] -> boom
j is now out of range of the valid indices of numbers, so when you attempt to access numbers[j] the behavior of your program becomes undefined. In this case, it crashed; the best possible outcome.
as the above comments pointed it out,
for (int i; i < numbers.size(); i++)
here 'int i' hides the previous local declaration of 'int i = 0;' (C4456), which is not desirable.
and the problem is that although i is bound to the range [0, n-1], j is not, which can cause access violation when j exceeds the range.
You can use below code which will pass your all test cases.
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
//first we will declare an additional vector which will return desired solution
vector<int> mult;
//by using two pointer approach
for(int i = 0; i<=nums.size(); i++){
for(int j = i+1; j<nums.size();j++){
//checking for condition
if(nums[i]+nums[j]==target){
mult.push_back(i);
mult.push_back(j);
j++;
return mult;
}
}
}
return mult;
}
};

How can I find the minimum number of swaps in a consecutive unordered array (vector)?

I am trying to solve a problem:
You are given an unordered array consisting of consecutive integers [1, 2, 3, ..., n] without any duplicates nor specific order.You are allowed to swap any two elements. You need to find the minimum number of swaps required to sort the array in ascending order.
CONSTRAINTS:
the number of elements must be >= 1
the elements in the array must be <= to the size of the array
My code works when the numbers are not in the right position, but when the element is in the right position it enters an infinite loop, example array: [1 3 5 2 4 6 7] <- My code doesn't work because it gets stuck on 1.
My code:
#include <iostream>
#include <vector>
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
int minimumSwaps(std::vector<int> arr)
{
int numberOfSwaps = 0;
int lastElementIndex = (arr.size() - 1);
bool isSwapping = true;
while (isSwapping)
{
isSwapping = false;
for (int i = 0; i < arr.size(); i++)
{
if (lastElementIndex - (arr.size() - arr[i]) != 0)
{
isSwapping = true;
swap(arr[i], arr[lastElementIndex - (arr.size() - arr[i])]);
numberOfSwaps++;
}
else
{
std::cout << arr[i] << " is already in its perfect position." << std::endl;
}
}
}
return numberOfSwaps;
}
P.S: I've just used the else statement to check what was going wrong.
Replacing lastElementIndex with its value (arr.size() - 1)
in line
if (lastElementIndex - (arr.size() - arr[i]) != 0)
yields
if ((arr.size() - 1) - (arr.size() - arr[i]) != 0)
and this is equivalent to
if (arr[i] != 1)
That's obviously wrong. Replace the line with
if (arr[i] - 1 != i)

Iteration variable goes out of range in for-loop

I have a for-loop in my function:
for (int i = vector1.size() - 1, j = vector2.size() - 1;i >= vector1.size() - Get_polynomial_power(vector1) - 1;--i, --j) {
// some code
something = vector1.at(i); // <- here i goes out of range
}
The problem is that iteration variable i goes out of range.
Condition for exiting from loop is set with i >= vector1.size() - Get_polynomial_power(vector1) - 1; which equals to i >= 0 in my specific case (Get_polynomial_power is user defined function that returns some int value).
And the last value of i is -1. So the program terminates with thrown exception "out of range".
But if I set condition for exiting the loop directly with 0, so it looks like:
for (int i = vector1.size() - 1, j = vector2.size() - 1;i >= 0;--i, --j) {
// some code
something = vector1.at(i); // <- here i doesn't go out of range
}
then there is no error and the last value of i is 0 so it doesn't go out of range.
So the question is: why doesn't iteration variable goes out of range if condition for exit from loop is set directly via 0, but if it is set with a statement that is equals to 0 then the error appears?
I tried a solution with loop-local value as was told in other similar questions, like:
for (int i = vector1.size() - 1, j = vector2.size() - 1;i >= vector1.size() - Get_polynomial_power(vector1) - 1;--i, --j) {
// some code
int index = i;
something = vector1.at(index);
}
but it didn't change the thing.
Just in case, here is full code of my function:
vector<int> Polynomial_addition_substraction(vector<int> polynomial1, vector<int> polynomial2) {
vector<int> addition_substraction_result;
vector<int> vector1;
vector<int> vector2;
if (Get_polynomial_power(polynomial1) >= Get_polynomial_power(polynomial2)) {
vector1 = polynomial1;
vector2 = polynomial2;
}
else {
vector1 = polynomial2;
vector2 = polynomial1;
}
for (int i = vector1.size() - 1, j = vector2.size() - 1;i>=vector1.size()-Get_polynomial_power(vector1)-1;--i,--j) {
if (j < 0) {
addition_substraction_result.insert(addition_substraction_result.begin(), vector1.at(i));
}
else {
addition_substraction_result.insert(addition_substraction_result.begin(), vector1.at(i) ^ vector2.at(j));
}
}
return addition_substraction_result;
}
The issue is due to .size() evaluating to an unsigned type and the subsequent subtraction happening therefore in unsigned arithmetic. (The int in an expression containing an unsigned and and int is converted to an unsigned.) This effect is particularly noticeable if the vector is empty.
So wraparound effects take the expression value to a large unsigned number, and that yields a subscripting error.
The solution is to write an expression of the form
i > size() - a
as
i + a > size()

Following coding problem SIGSEGV Runtime Error

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin>>T;
do{
vector<int> ans;
int N=0;
cin>>N;
vector<int> attackArray(N), defArray(N);
for (int i =0; i<N; i++) {
cin>>attackArray[i];
}
for (int i =0; i<N; i++) {
cin>>defArray[i];
}
for (int i =0; i<N; i++) {
int nexti, previ;
if (i == 0)
{
nexti = 1;
previ = N - 1;
}
else if (i == N - 1)
{
nexti = 0;
previ = N - 2;
}
else
{
nexti = i + 1;
previ = i - 1;
}
if (defArray[i] > attackArray[nexti] &&
defArray[i] > attackArray[previ] &&
defArray[i] > attackArray[nexti] + attackArray[previ]){
ans.push_back(defArray[i]);
}
else {ans.push_back(-1); break;}
}
sort(ans.begin(), ans.end(), greater<int>());
cout<<ans[0]<<endl;
T--;
}while (T !=0);
return 0;
}
Input
The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
The first line of each test case contains a single integer N.
The second line contains N space-separated integers a1,a2,…,aN.
The third line contains N space-separated integers d1,d2,…,dN.
Output
For each test case, print a single line containing one integer ― the best defense value of the shield the king gets, or −1 if Chef can be thrown in the snake pit.
Example
2
4
1 1 4 1
3 4 2 1
7
5 4 5 4 5 4 5
3 2 4 7 2 5 9
Example Output
3
-1
The problem is that your sequence of if statements should be one if ... else if ... else statement.
if (i == 0)
...
else if (i==N-1)
...
else
...
Just because a previous if condiition has evaluated to true doesn't stop code after the if statement from executing unless you use an else. So the condition in your third if statement is executing even when i == 0 or i == N - 1, resulting in an out of bounds array access and a crash.
Also
int attackArray[N],defArray[N];
is not legal C++ because all array sizes must be compile time constants. You are clearly using a compiler which doesn't care, but you should, so use this instead
vector<int> attackArray(N), defArray(N);
Finally there's a lot of duplicated code in your different conditions. You could simplify a lot by adding a couple of extra variables for the next and previous values of i. E.g.
int nexti, previ;
if (i == 0)
{
nexti = 1;
previ = N - 1;
}
else if (i == N - 1)
{
nexti = 0;
previ = N - 2;
}
else
{
nexti = i + 1;
previ = i - 1;
}
if (defArray[i] > attackArray[nexti] &&
defArray[i] > attackArray[previ] &&
defArray[i] > attackArray[nexti] + attackArray[previ])
...

C++ memory: deleting an unused array of bool can change the result from right to wrong

I am trying to solve Project Euler Problem 88, and I did it without too much effort; however, I find that some seemingly irrelevant code in my program is affecting the result. Here's my complete code (it's not short, but I cannot locate the error. I believe it would be obvious to more experienced eyes, so please read my description first):
#include <iostream>
#include <set>
using namespace std;
bool m[24001][12001];
bool p[24001]; // <------------ deleting this line will cause error in result!
long long answer[12001];
int main() {
long long i;
long long j;
long long l;
set<long long> all;
long long s = 0;
for (i = 0; i <= 24000; i++) {
for (j = 0; j <= 12000; j++) {
m[i][j] = false;
}
}
m[1][1] = true;
for (i = 2; i <= 24000; i++) {
m[i][1] = true;
for (j = 2; (j <= i) && (i * j <=24000); j++) {
for (l = 1; l <= i; l++) {
if (m[i][l]) {
m[i * j][l + 1 + (i * j) - i - j] = true;
}
}
}
}
for (i = 0; i <= 24000; i++) {
for (j = 0; j <= 12000; j++) {
if (m[i][j] && (answer[j] == 0)) {
answer[j] = i;
}
}
}
for (i = 2; i <= 12000; i++) {
cout << answer[i] << endl;
all.insert(answer[i]);
}
cout << all.size() << endl;
for (set<long long>::iterator it = all.begin(); it != all.end(); it++) {
//cout << *it << endl;
s += *it;
}
cout << s << endl;
}
With the "useless" bool array, all the answers are right, between 0 and 24000; but without it, some answers in the middle got corrupted and become very large numbers.
I am completely confused now; why would that unused array affect the middle of the answer array?
Thanks and sorry for the long code! I will be grateful if someone could edit the code into a better example, I simply son't know what is with the code.
You do a silly thing in here:
m[i * j][l + 1 + (i * j) - i - j] = true;
Say, i=160, j=150, l=1... You will try to access m[24000][23692]... And you corrupt the stack, so behavior is undefined.
Next time try to use some profiler and/or debugger.
Add:
#include <cassert>
at the begining and
assert( (i * j) * 12001 + (l + 1 + (i * j) - i - j) <= 12001*24001 );
before the following line:
m[i * j][l + 1 + (i * j) - i - j] = true;
The assertion will fail, which means you write outside the bounds of the array m.
As requested, adding this to an answer.
You are definitely writing beyond the bounds of the array m somewhere, when the unused array p exists, m overwrites in to its contents which doesn't affect the answer array but once p is removed the overwriting happens in to answer array showing up the problems.
Overwriting beyond the bounds of the array is an Undefined Behavior and it causes your program to be ill-formed. With Undefined Behavior all safe bets are off and any behavior is possible. While your program may work sometimes or crash sometimes or give incorrect results.Practically, Anything is possible and the behavior may or even may not be explainable.
In one of your nested loops you use l as the index for the second dimension. This variable can run from 0 to i and i, in turn, can run from 0 to 24000. Since your second dimension of the array can only be index from 0 to 12000 this causes a classic out of range error. This also nicely explains why adding an extra array avoid the problem: the out of range accesses go to the "unused" array rather than overwriting the result.