Dynamic Programming- Primitive Calculator - c++

The full explanation of the problem is here---http://imgur.com/a/UiE7L .
I've written the code, but it is showing segmentation error which I'm not able to solve. As per the logic of the program, I am saving the minimum number of operations needed to reach number n on the nth position of the array. I intend to go by this logic.
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
long long f(long long n, vector <long long> arr)
{
arr[1]=0;
arr.push_back(n);
long long ans=0, ret=0;
if (n==1)
{
return (0);
}
ans= f(n-1, arr) + 1;
if (n%2==0)
{
ret= f(n/2, arr) + 1;
if (ret<ans)
{
ans=ret;
std::cout<<ans<<'\n';
}
}
if (n%3==0)
{
ret= f(n/3, arr) + 1;
if (ret<ans)
{
ans=ret;
std::cout<<ans<<'\n';
}
}
arr[n]=ans;
return arr[n];
}
int main() {
long long n;
std::cin >> n;
std::vector<long long> arr;
std::cout<<f(n, arr);
return 0;
}

#include <bits/stdc++.h>
using namespace std;
long long f(long long n, vector <long long> arr)
{
arr[1]=0;
//arr.push_back(n); // not required
long long ans=0, ret=0;
if (n==1)
{
return (0);
}
ans= f(n-1, arr) + 1;
if (n%2==0)
{
ret= f(n/2, arr) + 1;
if (ret<ans)
{
ans=ret;
//std::cout<<ans<<'\n';
}
}
if (n%3==0)
{
ret= f(n/3, arr) + 1;
if (ret<ans)
{
ans=ret;
//std::cout<<ans<<'\n';
}
}
arr[n]=ans;
return arr[n];
}
int main() {
long long n = 120;
std::vector<long long> arr(n+1); // declare arr with size n+1
std::cout<<f(n, arr);
return 0;
}
You have accessed a[1] without declaring size of array >= 2 as array in c++ is 0 indexing and in addition to that if you provide array with some initial size as arr(n+1) while declaring then no need to push value of n in arr again.
then your solution works correct.
for itterative approach
#include <bits/stdc++.h>
using namespace std;
int main() {
long long n;
cin >> n;
vector<long long> arr(n+1);
for (int i = 1; i <= n; i++) {
arr[i] = arr[i - 1] + 1;
if (i % 2 == 0) arr[i] = min(1 + arr[i / 2], arr[i]);
if (i % 3 == 0) arr[i] = min(1 + arr[i / 3], arr[i]);
}
cout << arr[n]-1 << endl;
return 0;
}

Related

optimising count of inversion(i.e for i<j, a[i]>a[j]) for a large array

I am trying to count inversion(for eg.,for array [2,5,4,1] the inversion count is=4 namely (2,1),(5,4),(5,1),(4,1) using divide and conquer for a large set of arrays, I am getting a recursive count of value when a function executes each merge sort. I store all the count values in a vector and then again use sum operations, it works well for an array size of 70,000 but fails after it. I feel I am unnecessarily storing a large value to vector, instead, I am looking for a way to directly count the same but I am not getting a way to do the same, please help me in achieving it.
ps:the file link is this.
my code looks like;
#include<iostream>
#include<vector>
#include<fstream>
using namespace std;
long long greater_v(long long *array,long long ap,long long p){
long long numx=0;
for(long long i=0;i<p;i++){
if(array[i]>ap){
numx++;
}
}
return numx;
}
long long merge(long long U[],long long Lu,long long V[],long long Lv,long long S[],long long count1){
long long uf=0;long long vf=0;
for(long long sb=0;sb<Lu+Lv;sb++){
if(uf<Lu && vf<Lv){
if(U[uf]<V[vf]){
S[sb]=U[uf];uf++;}
else{
S[sb]=V[vf];
count1=count1+=greater_v(U,V[vf],Lu);
vf++;
}
}
else if(uf<Lu){
S[sb]=U[uf];uf++;
}
else{
S[sb]=V[vf];vf++;
}
}
return count1;
}
In this part I am looking for help where I am storing the value in the vector, instead, i want a way to directly count.
vector<unsigned long long int>v_val;
void MergeSort(long long arr[],long long n){
long long count=0;
//cout<<"sorting ";print(arr,n);
if(n==1)
return;
long long U[n/2];long long V[n-n/2];
for(long long i=0;i<n/2;i++){
U[i]=arr[i];
}
for(long long i=0;i<n-n/2;i++){
V[i]=arr[i+n/2];
}
MergeSort(U,n/2);
MergeSort(V,n-n/2);
count+=merge(U,n/2,V,n-n/2,arr,count);
v_val.push_back(count);
}
main function is;
int main(){
long long test_count=0;
ifstream file_num("pr_as_2.txt");
long long arr_num[100000];
for(long long i=0;i<100000;i++){
file_num>>arr_num[i];
}
unsigned long long int sum_val=0;
MergeSort(arr_num,70000);
for(size_t i=0;i<v_val.size();i++){
sum_val+=v_val[i];
}
cout<<sum_val;
}
look at this approach, it worked for me.
#include <bits/stdc++.h>
using namespace std;
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
unsigned int merge(int arr[], int temp[], int l, int m, int r) {
unsigned int inversions = 0;
int i = l;
int j = m;
int k = l;
while (i < m && j <= r) {
if (arr[i] <= arr[j]) {
temp[k] = arr[i];
i++;
} else {
temp[k] = arr[j];
j++;
inversions += m-i;
}
k++;
}
while (i < m) {
temp[k] = arr[i];
i++;
k++;
}
while (j <= r) {
temp[k] = arr[j];
j++;
k++;
}
for (int i = l; i <= r; i++) {
arr[i] = temp[i];
}
return inversions;
}
unsigned int count(int arr[], int temp[], int l, int r) {
unsigned int inversions = 0;
if (r > l) {
int m = (r+l)/2;
inversions = count(arr, temp, l, m);
inversions += count(arr, temp, m+1, r);
inversions += merge(arr, temp, l, m+1, r);
}
return inversions;
}
int main() {
int arr_size = 100000;
int arr[arr_size];
ifstream file("IntegerArray.txt");
string str;
int i = 0;
while (getline(file, str)) {
arr[i] = stoi(str);
i++;
}
// int arr[] = { 1, 20, 6, 4, 5 };
// int arr_size = sizeof(arr) / sizeof(arr[0]);
int temp[arr_size];
/* mergeSort(arr, 0, arr_size-1);
for (int i = 0; i < arr_size; i++) {
cout << arr[i] << " ";
} */
cout << count(arr, temp, 0, arr_size-1) << endl;
}

Dynamic Programming Fibonacci Number

I am trying to implement an approach using memoization for calculating the nth Fibonacci number.
#include <iostream>
#include <vector>
using namespace std;
int fib(int n, vector<int> v) {
int result = 0;
if (v[n] != 0) {
return v[n];
}
if (n == 1 || n == 2) {
result = 1;
}
else {
result = fib(n - 1, v) + fib(n - 2, v);
}
v[n] = result;
return result;
}
int main()
{
int n = 12;
vector<int> v(n + 1, 0);
cout << fib(n, v);
}
However, I get this error.
runtime error: addition of unsigned offset to 0x602000000110 overflowed to 0x60200000010c (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1043:34
How do I change the solution to resolve this problem? Thanks!
You are copying the vector for each call, so you don't fill initial the vector by numbers.
You have to use unsigned long long to calculate more numbers (actually 93 of them). int can fit only 46 (1836311903).
I would check the vector size inside of the function instead of creating it outside.
Use
unsigned long long fib(int n, vector <unsigned long long> &v) {
Full code: https://ideone.com/3Ipjgo
#include <iostream>
#include <vector>
using namespace std;
unsigned long long fib(int n, vector <unsigned long long> &v)
{
if (v.size() <= n)
v.resize(n + 1);
if (v[n])
return v[n];
return v[n] = n <= 2 ? 1 : fib(n - 1, v) + fib(n - 2, v);
}
int main()
{
vector <unsigned long long> v;
cout << fib(12, v) << endl;
for (int q=1; q<=94; ++q)
cout << q << ' ' << fib(q, v) << endl;
return 0;
}

Top Down Approach for this dynamic programming problem

Here is the problem-
You are given array B of size n. You have to construct array A such that 1<=A[i]<=B[i] and sum of the absolute difference of consecutive pairs of A is maximized ,that is, summation of abs(A[i]-A[i-1]) is maximised.You have to return this cost.
Example B=[1,2,3] A can be [1,2,1],[1,1,3],[1,2,3] In all these cases cost is 2 which is the maximum.
Constraints n<=10^5 ,1<=B[i]<=100
Here is my approach -
Cost will be maximum when A[i]=1 or A[i]=B[i]
So I created dp[idx][flag][curr] of size [100002][2][102] where it calculates the cost till index idx. flag will be 0 or 1 representing if A[i] should be 1 or B[i] respectively. curr will be the value of A[i] depending upon flag
Here is my code
#include<bits/stdc++.h>
using namespace std;
#define boost ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef long long int ll;
#define mod 1000000007
ll n;
ll dp[100002][2][101];
ll b[100005];
ll solve(ll idx,ll flag,ll curr)
{
if(idx>=n)
return 0;
ll s1=0;
if(dp[idx][flag][curr]!=-1)
return dp[idx][flag][curr];
if(idx==0)
{
int left=solve(idx+1,0,curr);
int right=solve(idx+1,1,curr);
return dp[idx][flag][curr]=max(left,right);
}
else
{
if(flag==0)
{
s1=abs(curr-1);
return dp[idx][flag][curr]=s1+max(solve(idx+1,0,1),solve(idx+1,1,1));
}
else
{
s1=abs(b[idx]-curr);
return dp[idx][flag][curr]=s1+max(solve(idx+1,0,b[idx]),solve(idx+1,1,b[idx]));
}
}
}
int main()
{
boost
ll t;
cin>>t;
while(t--)
{
cin>>n;
memset(dp,-1,sizeof(dp));
ll res=0;
for(int i=0;i<n;i++)
cin>>b[i];
ll s1=solve(0,0,1);//Starting from idx 0 flag 0 and value as 1
ll s2=solve(0,1,b[0]);//Starting from idx 0 flag 1 and value as B[0]
cout<<max(s1,s2)<<"\n";
}
}'
Is there any way to reduce states of dp or any other top down solution because my code fails if values of B[i] are large
You implement a recursive approach. Here, a simple iterative implementation allows to get a time efficiency of O(n) and a space efficiency of O(1)
(not counting the space needed for the input array).
You correctly stated that at index i, we have two choices only, a[i]=1 (flag = 0) or a[i]=b[i] (flag = 1)
The basic idea is that, when studying what choice to make at index i, we only need to know what are the optimum sums ending at index i-1, for flag = 0 (sum0) or flag = 1 (sum1).
We don't need to explicitely calculate the array a[.].
Note: I kept long long int as in your code, but it seems that int is quite enough here.
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
#define mod 1000000007 // needed ???
long long int sum_diff (const std::vector<long long> &b) {
int n = b.size();
long long int sum0 = 0;
long long int sum1 = 0;
for (int i = 1; i < n; ++i) {
long long int temp = std::max (sum0, sum1 + b[i-1] - 1); // flag = 0: a[i] = 1
sum1 = std::max (sum0 + b[i] - 1, sum1 + std::abs(b[i] - b[i-1])); // flag = 1: a[i] = b[i]
sum0 = temp;
}
return std::max (sum0, sum1);
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while(t--) {
int n;
std::cin >> n;
std::vector<long long int> b(n);
for(int i = 0;i < n; i++) std::cin >> b[i];
long long int s = sum_diff (b);
std::cout << s << "\n";
}
}
As you insist to have a top-down (recursive) aproach, I have implement both approaches in the following code. But I insist that the iterative solution is better in this case.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
int sum_diff (const std::vector<int> &b) {
int n = b.size();
int sum0 = 0;
int sum1 = 0;
for (int i = 1; i < n; ++i) {
int temp = std::max (sum0, sum1 + b[i-1] - 1); // flag = 0: a[i] = 1
sum1 = std::max (sum0 + b[i] - 1, sum1 + std::abs(b[i] - b[i-1])); // flag = 1: a[i] = b[i]
sum0 = temp;
}
return std::max (sum0, sum1);
}
void sum_diff_recurs (const std::vector<int> &b, int i, int&sum0, int &sum1) {
if (i == 0) {
sum0 = sum1 = 0;
return;
}
sum_diff_recurs (b, i-1, sum0, sum1);
int temp = std::max (sum0, sum1 + b[i-1] - 1); // flag = 0: a[i] = 1
sum1 = std::max (sum0 + b[i] - 1, sum1 + std::abs(b[i] - b[i-1])); // flag = 1: a[i] = b[i]
sum0 = temp;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while(t--) {
int n, sum0, sum1;
std::cin >> n;
std::vector<int> b(n);
for(int i = 0; i < n; i++) std::cin >> b[i];
int s = sum_diff (b);
std::cout << s << "\n";
sum_diff_recurs (b, n-1, sum0, sum1);
std::cout << std::max(sum0, sum1) << "\n";
}
}
Actually I found the solution using only two states idx and flag
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll n,k;
ll dp[100002][2];
ll b[100005];
ll solve(ll idx,ll flag)
{
if(idx>=n-1)
return 0;
if(dp[idx][flag]!=-1)
return dp[idx][flag];
ll val=(flag==1)?b[idx]:1;
ll left=solve(idx+1,0)+val-1;
ll right=solve(idx+1,1)+abs(val-b[idx+1]);
return (dp[idx][flag]=max(left,right));
}
int main()
{
ll t;
cin>>t;
while(t--)
{
cin>>n;
memset(dp,-1,sizeof(dp));
ll res=0;
for(int i=0;i<n;i++)
cin>>b[i];
ll s1=solve(0,0);
ll s2=solve(0,1);
cout<<max(s1,s2)<<"\n";
}
}

Non-Divisible Subset - Hackerrank

I am trying to solve the Non-Divisible Subset problem from Hackerrank (https://www.hackerrank.com/challenges/non-divisible-subset). I am trying to use the idea that if the sum of a and b is divisible by k, then a%k+b%k = k, however, it's not working very well.
Here is what I've written so far:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
int k;
cin >> n;
cin >> k;
int j;
vector<int>numbers;
vector<int>remainders;
for(int i = 0; i < n; i++) {
int z;
cin >> z;
numbers.push_back(z);
}
for (vector<int>::iterator it = numbers.begin(); it != numbers.end(); it++) {
j = *it % k;
remainders.push_back(j);
}
for(vector<int>::iterator it2 = remainders.begin(); it2 != remainders.end(); it2++) {
int remainderCount = 0;
int otherRemainderCount = 0;
otherRemainderCount = std::count(remainders.begin(), remainders.end(), k-*it2);
remainderCount = std::count(remainders.begin(), remainders.end(), *it2);
if (remainderCount > otherRemainderCount) {
theChosenOne = *it2;
} else if (otherRemainderCount > remainderCount) {
theChosenOne = k-*it2;
}
cout << theChosenOne << endl;
}
return 0;
}
I created a vector for the remainders and I am using the std::cout function to find out which remainder appears more in the vector. If K would be 5, *it2 = 4, and k-*it2 = 1. If *it2 appears more times, then I would choose *it2. Otherwise, I would choose k-*it2.
Your solution looks to be on the right track, but there is some change that is needed.
You basically need to hash the numbers in the array to proper location.
Have an array rem[k] initialised to 0.
Iterate over the n numbers in the array, and do the following:
rem[array[i]%k]++;
Now you have to deal with only the rem[] array, to find the maximum subset. The rem array has size of maximum k<=100. Make use of the small size of rem[] array to find the solution efficiently.
Edit: Adding the code for you.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n,i,k;
cin>>n>>k;
int arr[n];
int rem[k]={0};
for(i=0;i<n;i++)
{
cin>>arr[i];
}
for(i=0;i<n;i++)
{
rem[arr[i]%k]++;
}
int count = 0;
for(i=1;i<=k/2;i++)
{
count = count + max(rem[i],rem[k-i]);
}
count = count + (rem[0]>0?1:0);
if(k%2==0)
{
count = count - rem[k/2];
if(rem[k/2]>0)
count = count + 1;
}
cout<<count;
return 0;
}
After you have found out the contents of the rem[] array, its time to find the maximum subset. If you select rem[1] then you cannot select rem[k-1] as any two numbers, one from rem[1] and another from rem[k-1] can be summed together which will be divisible by k that we don't want. So we find whichever is maximum out of rem[i] and rem[k-i] and add it to the count
My code uses the above logic..
Hope it helps!!!
int main() {
int n,k;
cin>>n>>k;
vector <int> a(n);
vector <int> r(k,0);
for(int i=0;i<n;i++)
{
cin>>a[i];
r[a[i]%k]++;
}
int ctr=min(1,r[0]);
for(int a=1;a<(k/2+1);a++)
{
if(a!=k-a)
ctr+=max(r[a],r[k-a]);
}
if(k%2==0&&r[k/2]!=0)
ctr++;
cout<<ctr;
return 0;
}
This seemed to work
#include <stdio.h>
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int main() {
int n, k, a, total = 0;
scanf("%d %d", &n, &k);
int mods[k];
for (int i = 0; i < k; i++)
mods[i] = 0;
while (n--) {
scanf("%d", &a);
mods[a % k]++;
}
// can only have 1 value congruent to 0 mod k
total += min(1, mods[0]);
// if even, can only have 1 value congruent to k/2 mod k
if (k % 2 == 0)
total += min(1, mods[k / 2]);
// for all others, pick max of those k and n-k mod k
for (int d = 1; d < (k + 1) / 2; d++) { // for all others,
total += max(mods[d], mods[k - d]);
}
printf("%d", total);
return 0;
}

Minimum difference in an array

I want to find the minimum difference among all elements of an array. I read through various other questions, but couldn't find the exact source of the error in the following code.
#include<iostream>
#include<stdio.h>
#include<cstdlib>
using namespace std;
void quicksort(long int *lp, long int *rp);
int main()
{
int t,n;
long int s[5000];
cin>>t;
while(t--){
cin>>n;
for(int i=0;i<n;i++) cin>>s[i];
quicksort(&s[0],&s[n-1]);
//cout<<"passes:"<<passes<<endl;
//for(int i=0;i<n;i++) cout<<s[i]<<" ";
long int min = abs(s[1]-s[0]);
//cout<<endl<<min;
for(int i=1;i<(n-1);i++){
long int temp = abs(s[i]-s[i+1]);
if (temp <= min) min = temp;
}
cout<<min;
}
}
void quicksort(long int *lp,long int *rp){
int arraysize= (rp-lp)+1;
if(arraysize > 1){
long int *pivot = (lp+(arraysize/2));
long int swap=0;
long int *orgl = lp;
long int *orgr = rp;
while(lp!=rp){
while (*lp < *pivot) lp++;
while (*rp > *pivot) rp--;
if (lp == pivot) pivot=rp;
else if (rp == pivot) pivot=lp;
swap = *lp;
*lp = *rp;
*rp = swap;
if((*lp == *pivot) || ( *rp == *pivot)) break;
}
quicksort(orgl,pivot-1);
quicksort(pivot+1,orgr);
}
}
The problem statement is given in this link : http://www.codechef.com/problems/HORSES
Can you please identify the error in my program ?
You are using C++ so instead of using your custom quicksort which is not really guarantee O(n*logn) you better use sort from <algorithm>.
This logic looks good:
long int min = abs(s[1]-s[0]);
//cout<<endl<<min;
for(int i=1;i<(n-1);i++){
long int temp = abs(s[i]-s[i+1]);
if (temp <= min) min = temp;
}
By the way:
cout<<min;
Add cout<<min << endl;
The line
if((*lp == *pivot) || ( *rp == *pivot)) break;
is wrong. Consider
5 4 7 5 2 5
^
pivot
Oops.
This line
long int temp = abs(s[i]-s[i+1]);
is unnecessarily complex. Since the array is (supposedly) sorted,
long int temp = s[i+1] - s[i];
does the same without calling abs.
sort(s, s + n); // #include <algorithm> O(n*log n)
Otherwise sort/find minimum algorithm is correct. There are O(n) algorithms based on randomization, bucket sort.
#include <algorithm> // sort()
#include <iostream>
int main() {
using namespace std;
int ntests, n;
const int maxn = 5000; // http://www.codechef.com/problems/HORSES
int s[maxn];
cin >> ntests; // read number of tests
while (ntests--) {
cin >> n; // read number of integers
for (int i = 0; i < n; ++i) cin >> s[i]; // read input array
sort(s, s + n); // sort O(n*log n)
// find minimal difference O(n)
int mindiff = s[1] - s[0]; // minn = 2
for (int i = 2; i < n; ++i) {
int diff = s[i] - s[i-1];
if (diff < mindiff) mindiff = diff;
}
cout << mindiff << endl;
}
}
#include <iostream> using namespace std;
int main() {
int a[] = {1,5,2,3,6,9};
int c=0;
int n = sizeof(a)/sizeof(a[0]);
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
cout<<a[i]<<" - "<<a[j]<<" = "<<a[i]-a[j]<<endl;
if(abs(a[i]-a[j]) == 2)
c++;
}
}
cout<<c<<endl;
return 0; }