So, I was solving a question which goes like this:
Given a list of n integers, A={a1,a2,…,an}, and another integer, k representing the expected sum. Select zero or more numbers from A such that the sum of these numbers is as near as possible, but not exceeding, to the expected sum (k).
Note
Each element of A can be selected multiple times.
If no element is selected then the sum is 0.
Input Format
The first line contains T the number of test cases.
Each test case comprises of two lines. First line contains two integers, n k, representing the length of list A and expected sum, respectively. Second line consists of n space separated integers, a1,a2,…,an, representing the elements of list A.
Constraints:
1 ≤ T ≤ 10
1 ≤ n ≤ 2000
1 ≤ k ≤ 2000
1 ≤ ai ≤ 2000, where i∈[1,n]
Output Format
Output T lines, the maximum sum for each test case which is as near as possible, but not exceeding, to the expected sum (k).
Here is the problem link: https://www.hackerrank.com/challenges/unbounded-knapsack
Now, I developed a top-down approach for this as follows:
int knapsack(int arr[],int n, int Sum, int dp[][1000])
{
if ( n < 0 || Sum < 0 )
return 0;
if(n==0||Sum==0)
{
dp[Sum][n] = 0;
return 0;
}
if (arr[n-1] == Sum)
{
dp[Sum][n-1] = arr[n-1];
return arr[n-1];
}
else if (dp[Sum][n] != -1)
return dp[Sum][n];
else if(arr[n-1] > Sum)
{
dp[Sum][n] = knapsack(arr,n-1,Sum,dp);
return dp[Sum][n];
}
else //gets selected or doesn't get selected
{
dp[Sum][n] = max( arr[n-1] + knapsack(arr,n,(Sum-arr[n-1]),dp) , knapsack(arr,n-1,Sum,dp) );
return dp[Sum][n];
}
}
However, the above gives a Seg fault when the input is given as:
1
5 9
3 4 4 4 8
I tried debugging it but it shows a Seg-fault at the beginning of the function after many recursive calls. Am I missing out any condition?
In your else:
dp[Sum][n] = max( arr[n-1] + knapsack(arr,n,(Sum-arr[n-1]),dp) , knapsack(arr,n-1,Sum,dp) );
It should be n - 1 as well, because you're done with the current element no matter what. Like it is now, it will do more recursive calls than necessary. With this fix, the segfault is gone on my PC and the function returns 0.
dp[Sum][n] = max( arr[n-1] + knapsack(arr,n-1,(Sum-arr[n-1]),dp) , knapsack(arr,n-1,Sum,dp) );
This program correctly returns 8 as the answer for your example:
int knapsack(int arr[],int n, int Sum, int dp[][1000]);
int main()
{
int t;
int n,k;
cin>>t;
int i,j;
int dp[1000][1000];
for(int i=0;i<t;i++)
{
for ( i = 0; i < 1000; i++ )
for ( j = 0; j < 1000; j++ )
dp[i][j] = -1;
int a[2000];
cin>>n>>k;
for(int j=0;j<n;j++)
cin>>a[j]; // you had i here
while (knapsack(a,n - 1,k,dp) == 0) // lower k until we can build it exactly
--k;
cout << k << endl;
}
return 0;
}
// knapsack(n, Sum) = true if we can use the first n elements to build Sum exactly
int knapsack(int arr[],int n, int Sum, int dp[][1000])
{
if (Sum < 0 )
return 0;
if(n < 0)
{
return Sum == 0;
}
else if (dp[Sum][n] != -1)
return dp[Sum][n];
else //gets selected or doesn't get selected
{
dp[Sum][n] = knapsack(arr,n-1,(Sum-arr[n]),dp) || knapsack(arr,n-1,Sum,dp);
}
return dp[Sum][n];
}
If you can use the same element more than once, I suggest the following iterative approach with a simple one dimensional array:
dp[0] = true
s = 0
for i = 0 to number of elements:
s += elements[i]
for j = elements[i] to s:
dp[j] = dp[j] || dp[j - elements[i]]
Where dp[x] = true if we can build sum x.
Your other bug is:
for(int j=0;j<n;j++)
cin>>a[i];
Notice the i where you meant j
Related
How to count comparisons in selectionsort?
terms:
when the statements you perform to find the maximum value is 'true'
then count comparison.
The value to get the maximum value is held at the first element in the array, not at random.
I try with C
variable count position change - no work
new variable 'first' , first=sort[MAX] insert first for loop, - no work
#include <stdio.h>
int main() {
int sort[10000], i, n, MAX, temp, count;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &sort[i]);
}
for (MAX = 0; MAX < n; MAX++)
for (i = MAX + 1; i < n; i++) {
if (sort[MAX] > sort[i]) {
count++;
temp = sort[MAX];
sort[MAX] = sort[i];
sort[i] = temp;
}
}
printf("%d ", count);
return 0;
}
Sample Input
10
0 7 1 6 7 7 6 6 5 4
Sample Output
17
EDIT: new code:
#include <stdio.h>
#define SWAP(x, y, temp) ( (temp)=(x), (x)=(y), (y)=(temp) )
int count = 0;
void selection_sort(int list[], int n) {
int i, j, least, temp;
for (i = 0; i < n - 1; i++) {
least = i;
for (j = i + 1; j < n; j++) {
if (list[j] < list[least]) {
least = j;
count++;
}
}
SWAP(list[i], list[least], temp);
}
}
int main() {
int list[10000], i, n;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &list[i]);
};
selection_sort(list, n);
printf("%d", count);
}
how about this? why this code didn't move too?
You aren't counting the right thing, this code
if(sort[MAX]>sort[i])
{
count++;
temp=sort[MAX];
sort[MAX]=sort[i];
sort[i]=temp;
}
counts the times that two numbers are swapped. But you want to count comparisons so it should be this
count++;
if(sort[MAX]>sort[i]) // this is what we are counting
{
temp=sort[MAX];
sort[MAX]=sort[i];
sort[i]=temp;
}
Another problem is that you don't give count an initial value of zero
int sort[10000],i,n,MAX,temp,count;
should be
int sort[10000],i,n,MAX,temp,count = 0;
how to count comparison selectionsort?
Your definition of the term is oddly worded, but it seems to be intended to focus on the essential comparisons of the algorithm, as opposed to comparisons performed incidentally for other purposes, or inside library functions. That is, in the implementation you present (whose correctness I do not evaluate), you're to count each evaluation of sort[MAX]>first, but not MAX<n or i<n.
You appear to be using variable count for that purpose, but you are counting only comparisons that evaluate to true. My interpretation of the problem, based both on the wording presented and on my general expectations for such a problem, is that every evaluation of sort[MAX]>first should be counted, regardless of the result. That would be achieved by lifting the expression count++ out of the if block, but leaving it inside the inner enclosing for loop.
Of course, as #john observes, you do need to initialize count to 0 before beginning to sort. You might luck into getting that by accident, but the initial value of a local variables without an initializer is indeterminate (at least) until a value is assigned.
i try with c variable count position change - no work
new variable 'first' , first=sort[MAX] insert first for loop, - no work
Even with the misplacement of your increment to count, if your sort were in fact working then you would expect to see some counts for most inputs. That you don't is a good sign that your sort in fact does not work correctly. I would suggest outputting also the the sorted results so that you can debug the details of the sort algorithm.
You could abstract out the comparison into a function or macro that also increments a counter. The macro approach could be
#define GT(x,y,counter) (counter++, (x) > (y) ? 1 : 0)
...
if ( GT( sort[MAX], sort[i], count ) == 1 )
{
// perform swap
}
whereas the function approach would be
int gt( int x, int y, int *counter )
{
(*counter)++;
if ( x > y )
return 1;
return 0;
}
...
if ( gt( sort[MAX], sort[i], &count ) == 1 )
{
// perform swap
}
You are counting the number of swaps, not the number of comparisons.
Here is a corrected without a global variable and a few extra checks:
#include <stdio.h>
#define SWAP(x, y, temp) ((temp) = (x), (x) = (y), (y) = (temp))
int selection_sort(int list[], int n) {
int count = 0;
int i, j, least, temp;
for (i = 0; i < n - 1; i++) {
least = i;
for (j = i + 1; j < n; j++) {
count++;
if (list[j] < list[least]) {
least = j;
}
}
SWAP(list[i], list[least], temp);
}
return count;
}
int main() {
int list[10000], i, n, count;
if (scanf("%d", &n) != 1 || n > 10000)
return 1;
for (i = 0; i < n; i++) {
if (scanf("%d", &list[i]) != 1)
return 1;
}
count = selection_sort(list, n);
printf("%d\n", count);
return 0;
}
Not however that your algorithm will always perform the same number of comparisons for any set of n values: n * (n - 1) / 2 comparisons, and since you do not test of i != least, it will perform n - 1 swaps.
I'm making a simple program to calculate the number of pairs in an array that are divisible by 3 array length and values are user determined.
Now my code is perfectly fine. However, I just want to check if there is a faster way to calculate it which results in less compiling time?
As the length of the array is 10^4 or less compiler takes less than 100ms. However, as it gets more to 10^5 it spikes up to 1000ms so why is this? and how to improve speed?
#include <iostream>
using namespace std;
int main()
{
int N, i, b;
b = 0;
cin >> N;
unsigned int j = 0;
std::vector<unsigned int> a(N);
for (j = 0; j < N; j++) {
cin >> a[j];
if (j == 0) {
}
else {
for (i = j - 1; i >= 0; i = i - 1) {
if ((a[j] + a[i]) % 3 == 0) {
b++;
}
}
}
}
cout << b;
return 0;
}
Your algorithm has O(N^2) complexity. There is a faster way.
(a[i] + a[j]) % 3 == ((a[i] % 3) + (a[j] % 3)) % 3
Thus, you need not know the exact numbers, you need to know their remainders of division by three only. Zero remainder of the sum can be received with two numbers with zero remainders (0 + 0) and with two numbers with remainders 1 and 2 (1 + 2).
The result will be equal to r[1]*r[2] + r[0]*(r[0]-1)/2 where r[i] is the quantity of numbers with remainder equal to i.
int r[3] = {};
for (int i : a) {
r[i % 3]++;
}
std::cout << r[1]*r[2] + (r[0]*(r[0]-1)) / 2;
The complexity of this algorithm is O(N).
I've encountered this problem before, and while I don't find my particular solution, you could improve running times by hashing.
The code would look something like this:
// A C++ program to check if arr[0..n-1] can be divided
// in pairs such that every pair is divisible by k.
#include <bits/stdc++.h>
using namespace std;
// Returns true if arr[0..n-1] can be divided into pairs
// with sum divisible by k.
bool canPairs(int arr[], int n, int k)
{
// An odd length array cannot be divided into pairs
if (n & 1)
return false;
// Create a frequency array to count occurrences
// of all remainders when divided by k.
map<int, int> freq;
// Count occurrences of all remainders
for (int i = 0; i < n; i++)
freq[arr[i] % k]++;
// Traverse input array and use freq[] to decide
// if given array can be divided in pairs
for (int i = 0; i < n; i++)
{
// Remainder of current element
int rem = arr[i] % k;
// If remainder with current element divides
// k into two halves.
if (2*rem == k)
{
// Then there must be even occurrences of
// such remainder
if (freq[rem] % 2 != 0)
return false;
}
// If remainder is 0, then there must be two
// elements with 0 remainder
else if (rem == 0)
{
if (freq[rem] & 1)
return false;
}
// Else number of occurrences of remainder
// must be equal to number of occurrences of
// k - remainder
else if (freq[rem] != freq[k - rem])
return false;
}
return true;
}
/* Driver program to test above function */
int main()
{
int arr[] = {92, 75, 65, 48, 45, 35};
int k = 10;
int n = sizeof(arr)/sizeof(arr[0]);
canPairs(arr, n, k)? cout << "True": cout << "False";
return 0;
}
That works for a k (in your case 3)
But then again, this is not my code, but the code you can find in the following link. with a proper explanation. I didn't just paste the link since it's bad practice I think.
Given a natural number n (1 <= n <= 500000), please output the summation of all its proper divisors.
Definition: A proper divisor of a natural number is the divisor that is strictly less than the number.
e.g. number 20 has 5 proper divisors: 1, 2, 4, 5, 10, and the divisor summation is: 1 + 2 + 4 + 5 + 10 = 22.
<<--This is a challenge i am trying to do and i am using recursion
int find_sum(std::vector <int> nums,long int sum,int num_now,long int j)
{
if(j<nums[num_now])
{
if(nums[num_now]%j==0)
{
sum=sum+j;
}
return find_sum(nums,sum,num_now,j+1);
}
else
{
return sum;
}
}
sum is the sum of all divisors,nums is the vector i stored number in,num_now is current member in vector,int j is 1 i use it to search for dividers,sadly using this i cant use numbers like 500000 it give's me error,is there any better way to do it or have i made a mistake somewhere.
--Thank you for your time
Here is a recursive way to solve your problem:
int find_sum(int x, int i)
{
if(i == 0)
return 0;
if(x % i == 0)
return i + find_sum(x, (i-1));
return find_sum(x, (i-1));
}
You need to call find_sum(N, N-1); in order to find sum of dividers of N (i must be less than given N because of strict inequality).
In your case it would be find_sum(20, 19);
e.g. my function returns:
71086 for N = 50000
22 for N = 20
0 for N = 1
I don't see the reason why you need to use recursion for solving this problem. I would prefer a more staightforward way to solve it.
long CalculateSumOfDivisors(int number)
{
long sum = 0;
for(int i=1; i<number; i++)
{
// If the remainder of num/i is zero
// then i divides num. So we add it to the
// current sum.
if(number%i==0)
{
sum+=i;
}
}
return sum;
}
Furthermore, we could write a more optimal algorithm, if we note the following:
Let that we have a number n and d is the smallest divisor of n that is greater of 1. (Apparently if the number n is a prime number there is any such a divisor). Then the larget divisor of n is the number n/d.
Based on this we can formulate a more optimal algorithm.
long CalculateSumOfDivisors(int number)
{
int smallestDivisor = FindSmallestDivisor(number);
if(smallestDivisor==1) return 1;
long sum = smallestDivisor;
// Calculate the possible greatest divisor.
int possibleGreatestDivisor = (int)floor(number/smallestDivisor);
for(int i=smallestDivisor+1; i<=possibleGreatestDivisor; i++)
{
if(number%i==0)
{
sum+=i;
}
}
return sum;
}
int FindSmallestDivisor(int number)
{
int smallestDivisor = 1;
for(int i=2; i<number; i++)
{
if(number%i==0)
{
smallestDivisor = i;
break;
}
}
return smallestDivisor;
}
I tried writing code with main function asking user to give the it wants to get sum of. here is the code , hope it helps.
#include<iostream>
using namespace std;
int Sum(int min, int max, int &val, int &sum){
if(min >= max)
return 0;
for ( ; min < max; min++){
if ( val%min == 0){
sum += min + val/min;
return Sum(++min,val/min, val,sum);
}
}
return 0;
}
int main(){
int s=1;
int val;
cout <<"Enter Val to sum:";
cin >> val;
Sum(2,val,val,s);
cout <<"Sum is :"<<s<<endl;
return 0;
}
Here Sum function is used recursively and passed parameters as shown in the code.
Hope it helps.
I don't think you should use recursion.
Instead start by looping from 1..N-1
When you find a divisor adjust the end value for the loop. Example if 2 is a divisor then you know N/2 is also a divisor. And just as important you know there can be no further divisors in the range ]N/2:N[. Likewise if 3 is a divisor then you know N/3 is also a divisor and you know there are no more divisors in the range ]N/3:N[.
Following that concept you can reduced the number of loops significantly for most numbers.
Something like:
long find_sum(int num)
{
long sum = 0;
int max = num;
int i = 1;
while(i < max)
{
if(num % i == 0)
{
sum += i; // Add i to the sum
max = num / i; // Decrement max for performance
if (max != i && max != num)
{
sum += max; // Add max when max isn't equal i
}
}
i++;
}
return sum;
}
Example:
num = 10
sum = 0
i = 1 -> sum = 1, max = 10
i = 2 -> sum = 1+2+5, max = 5
i = 3 -> sum = 1+2+5, max = 5
i = 4 -> sum = 1+2+5, max = 5
i = 5 -> return 8 (1+2+5)
num = 64
sum = 0
i = 1 -> sum = 1, max = 64
i = 2 -> sum = 1+2+32, max = 32
i = 3 -> sum = 1+2+32, max = 32
i = 4 -> sum = 1+2+32+4+16, max = 16
i = 5 -> sum = 1+2+32+4+16, max = 16
i = 6 -> sum = 1+2+32+4+16, max = 16
i = 7 -> sum = 1+2+32+4+16, max = 16
i = 8 -> sum = 1+2+32+4+16+8, max = 8
i = 9 -> return (1+2+32+4+16+8)
The number of loops are kept down by changing max whenever a new divisor is found.
Given a sequence of n positive integers we need to count consecutive sub-sequences whose sum is divisible by k.
Constraints : N is up to 10^6 and each element up to 10^9 and K is up to 100
EXAMPLE : Let N=5 and K=3 and array be 1 2 3 4 1
Here answer is 4
Explanation : there exists, 4 sub-sequences whose sum is divisible by 3, they are
3
1 2
1 2 3
2 3 4
My Attempt :
long long int count=0;
for(int i=0;i<n;i++){
long long int sum=0;
for(int j=i;j<n;j++)
{
sum=sum+arr[j];
if(sum%k==0)
{
count++;
}
}
}
But obviously its poor approach. Can their be better approach for this question? Please help.
Complete Question: https://www.hackerrank.com/contests/w6/challenges/consecutive-subsequences
Here is a fast O(n + k) solution:
1)Lets compute prefix sums pref[i](for 0 <= i < n).
2)Now we can compute count[i] - the number of prefixes with sum i modulo k(0 <= i < k).
This can be done by iterating over all the prefixes and making count[pref[i] % k]++.
Initially, count[0] = 1(an empty prefix has sum 0) and 0 for i != 0.
3)The answer is sum count[i] * (count[i] - 1) / 2 for all i.
4)It is better to compute prefix sums modulo k to avoid overflow.
Why does it work? Let's take a closer a look at a subarray divisible by k. Let's say that it starts in L position and ends in R position. It is divisible by k if and only if pref[L - 1] == pref[R] (modulo k) because their differnce is zero modulo k(by definition of divisibility). So for each fixed modulo, we can pick any two prefixes with this prefix sum modulo k(and there are exactly count[i] * (count[i] - 1) / 2 ways to do it).
Here is my code:
long long get_count(const vector<int>& vec, int k) {
//Initialize count array.
vector<int> cnt_mod(k, 0);
cnt_mod[0] = 1;
int pref_sum = 0;
//Iterate over the input sequence.
for (int elem : vec) {
pref_sum += elem;
pref_sum %= k;
cnt_mod[pref_sum]++;
}
//Compute the answer.
long long res = 0;
for (int mod = 0; mod < k; mod++)
res += (long long)cnt_mod[mod] * (cnt_mod[mod] - 1) / 2;
return res;
}
That have to make your calculations easier:
//Now we will move all numbers to [0..K-1]
long long int count=0;
for(int i=0;i<n;i++){
arr[i] = arr[i]%K;
}
//Now we will calculate cout of all shortest subsequences.
long long int sum=0;
int first(0);
std::vector<int> beg;
std::vector<int> end;
for(int i=0;i<n;i++){
if (arr[i] == 0)
{
count++;
continue;
}
sum += arr[i];
if (sum == K)
{
beg.push_back(first);
end.push_back(i);
count++;
}
else
{
while (sum > K)
{
sum -= arr[first];
first++;
}
if (sum == K)
{
beg.push_back(first);
end.push_back(i);
count++;
}
}
}
//this way we found all short subsequences. And we need to calculate all subsequences that consist of some short subsequencies.
int party(0);
for (int i = 0; i < beg.size() - 1; ++i)
{
if (end[i] == beg[i+1])
{
count += party + 1;
party++;
}
else
{
party = 0;
}
}
So, with max array size = 10^6 and max size of rest = 99, you will not have overflow even if you will need to summ all numbers in simple int32.
And time you will spend will be around O(n+n)
I was trying to do this question i came across while looking up interview questions. We are asked the number of ways of placing r coins on a n*m grid such that each row and col contain at least one coin.
I thought of a backtracking solution, processing each cell in the grid in a row major order, I have set up my recursion in this way. Seems my approach is faulty because it outputs 0 every time. Could someone please help me find the error in my approach. ? Thanks.
constraints. n , m < 200 and r < n*m;
Here is the code i came up with.
#include<cstdio>
#define N 201
int n, m , r;
int used[N][N];
int grid[N][N] ; // 1 is coin is placed . 0 otherwise. // -1 undecided.
bool isOk()
{
int rows[N];
int cols[N];
for(int i = 0 ; i < n ; i++) rows[i] = 0;
for(int i = 0 ; i < m ; i++) cols[i] = 0;
int sum = 0;
for(int i = 0 ; i < n ; i++)for(int j = 0; j < m ; j++)
{
if(grid[i][j]==1)
{
rows[i]++;
cols[j]++;
sum++;
}
}
for(int i = 0 ; i < n ; i++)
{
if(rows[i]==0) return false;
}
for(int j = 0 ; j < n ; j++)
{
if(cols[j]==0) return false;
}
if(sum==r) return true;
else return false;
}
int calc_ways(int row , int col, int coins)
{
if(row >= n) return 0;
if(col >= m) return 0;
if(coins > r) return 0;
if(coins == r)
{
bool res = isOk();
if(res) return 1;
else 0;
}
if(row == n - 1 and col== m- 1)
{
bool res = isOk();
if(res) return 1;
else return 0;
}
int nrow, ncol;
if(col + 1 >= m)
{
nrow = row + 1;
ncol = 0;
}
else
{
nrow = row;
ncol = col + 1;
}
if(used[row][col]) return calc_ways(nrow, ncol, coins);
int ans = 0;
used[row][col] = 1;
grid[row][col] = 0;
ans += calc_ways(nrow , ncol , coins);
grid[row][col] = 1;
ans += calc_ways(nrow , ncol , coins + 1);
return ans;
}
int main()
{
int t;
scanf("%d" , &t);
while(t--)
{
scanf("%d %d %d" , &n , &m , &r);
for(int i = 0 ; i <= n ; i++)
{
for(int j = 0; j <= m ; j++)
{
used[i][j] = 0;
grid[i][j] = -1;
}
}
printf("%d\n" , calc_ways(0 , 0 , 0 ));
}
return 0;
}
You barely need a program to solve this at all.
Without loss of generality, let m <= n.
To begin with, we must have n <= r, otherwise no solution is possible.
Then, we subdivide the problem into a square of size m x m, on to which we will place m coins along the major diagonal, and a remainder, on to which we will place n - m coins so as to fulfil the remaining condition.
There is one way to place the coins along the major diagonal of the square.
There are m^(n - m) possibilities for the remainder.
We can permute the total so far in n! ways, although some of those will be duplicates (how many is left as an exercise for the student).
Furthermore, there are r - n coins left to place and (m - 1)n places left to put them.
Putting these all together we have an upper bound of
1 x m^(n - m) x n! x C((m - 1)n, r - n)
solutions to the problem. Divide this number by the number of duplicate permutations and you're done.
Problem 1
The code will start by placing a coin on each square and marking each square as used.
It will then test the final position and decide that the final position does not meet the goal of r coins.
Next it will start backtracking, but will never actually try another choice because used[row][col] is set to 1 and this shortcircuits the code to place coins.
In other words, one problem is that entries in "used" are set, but never cleared during the recursion.
Problem 2
Another problem with the code is that if n,m are of size 200, then it will never complete.
The issue is that this backtracking code has complexity O(2^(n*m)) as it will try all possible combinations of placing coins (many universe lifetimes for n=m=200...).
I would recommend you look at a different approach. For example, you might want to consider dynamic programming to compute how many ways there are of placing "k" coins on the remaining "a" columns of the board such that we make sure that we place coins on the "b" rows of the board that currently have no coins.
It can be treated as total ways in which d grid can b filled with r coins -(total ways leaving a single row nd filling in d rest -total ways leaving a single column nd filling in d rest- total ways leaving a row nd column together nd filling d rest) which implies
p(n*m ,r) -( (p((n-1)*m , r) * c(n,1)) +(p((m-1)*n , r) * c(m,1))+(p((n-1)*(m-1) , r) * c(n,1)*c(m,1)) )
I just think so but not sure of it!