The problem from uva OJ
my solution with recursion
#include <cstdio>
using namespace std;
#define garbaze 0
//number of ways changes can be made
int coins[] = {garbaze,50,25,10,5,1}; //order does not matter//as in the //count_ways... function we are returning
//0 if which_coin_now is <= 0 so it
//does n't matter what we have in the index 0 [garbaze] .. but we must put //something there to implement the
//code using the pseudo code or recursive relation
typedef unsigned long long ull; //simple typedef
ull dp[7490][6]; //2d table
//recursive approach
ull count_ways_of_changes(int money_now,int which_coin_now)
{
if(money_now == 0)
return 1;
if(money_now < 0 || which_coin_now <=0 )
return 0;
if(dp[money_now][which_coin_now] == -1)
dp[money_now][which_coin_now] = count_ways_of_changes(money_now,which_coin_now-1) //excluding current coin
+ count_ways_of_changes(money_now - coins[which_coin_now],which_coin_now) ; //including current coin
return dp[money_now][which_coin_now] ;
}
int main()
{
for(int loop = 0; loop< 7490 ;loop++)
for(int sec_loop = 0;sec_loop<6;sec_loop++)
dp[loop][sec_loop] = -1; //table initialization
int N = 0;
while(scanf("%d",&N)==1)
{
printf("%llu\n",count_ways_of_changes(N,5)); //llu for unsigned long long
}
return 0;
}
This one got accepted (and took 0.024 s)
And my iterative approach :
#include <cstdio>
//#include <iostream>
//using namespace std;
typedef unsigned long long ull;
ull dp[7490][6];
#define garbaze 0
int value_coins[] = {garbaze,5,1,10,25,50} ;
inline ull count_ways_change(int money,int num_of_coins)
{
for(int sum_money_now = 0; sum_money_now <= money ;sum_money_now++)
for(int recent_coin_index = 0 ; recent_coin_index <= num_of_coins ; recent_coin_index++)
//common mistakes : starting the second index at num_of_coins and decrementing till 0 ...see we are pre calculating
//we have to start bottom to up....if we start at dp[0][5] .....to dp[1][5] but to know that i need to know
//dp[1][4] and dp[..][5] before hand ..but we have not calculated dp[1][4] yet...in this case i don't go to infinite
//loop or anything as the loop is well defined but i get stupid garbaze answer
{
if(sum_money_now == 0)
dp[sum_money_now][recent_coin_index] = 1;
else if(recent_coin_index == 0)
dp[sum_money_now][recent_coin_index] = 0;
else if(sum_money_now < value_coins[recent_coin_index] && recent_coin_index != 0)
dp[sum_money_now][recent_coin_index] = dp[sum_money_now][recent_coin_index-1] ;
else
dp[sum_money_now][recent_coin_index] = dp[sum_money_now][recent_coin_index-1] + dp[sum_money_now - value_coins[recent_coin_index] ][recent_coin_index] ;
// cout<<dp[sum_money_now][recent_coin_index]<<endl;
}
return dp[money][num_of_coins] ;
}
int main()
{/*
for(int loop = 0; loop< 7490 ;loop++)
for(int sec_loop = 0;sec_loop<6;sec_loop++)
dp[loop][sec_loop] = -1; //table initialization
*/ //In the iterative version do not need to initialize the table as we are working bottom - up
int N = 0;
while(scanf("%d",&N)==1)
{
printf("%llu\n",count_ways_change(N,5)); //llu for unsigned long long
}
return 0;
}
But i got time limit exceeded for this one.It gives correct output but i don't see a reason why this one has to be so slow?
The difference is your recursive solution remember partial solutions from previous tasks (because the DP table is global and does not get removed between different inputs), while the iterative doesn't - for each new input, it recalculates the DP matrix from scratch.
It can be solved by remembering which portion of the DP table was already calculated and avoid recalculating it, rather than recalculate it from scratch for every query.
Related
I'm trying to write a c++ program which gets an integer n (n>=1 && n<=100000) from the user and puts the sum of its digits into b. The output needed is the b-th prime number coming after n. I'm an absolute beginner in programming so I don't know what's wrong with the for loop or any other code that it doesn't show the correct output. For example the 3rd prime number after 12 (1+2=3) is 19 but the loop counts the prime numbers from 2 instead of 12, so it prints 7 as result.
#include <iostream>
using namespace std;
bool isPrime(int n)
{
if(n <= 1)
return false;
for(int i = 2; i <= (n/2); i++)
if(n % i == 0)
return false;
return true;
}
int main()
{
long int n;
int b = 0;
cin>>n;
while(n >= 1 && n <= 100000){
b += n % 10;
n /= 10;
}
for(int i = n, counter = b; counter <= 10; i++)
if(isPrime(i)){
counter++;
if(i > n)
cout<<counter<<"th prime number after n is : "<<i<<endl;
}
return 0;
}
So one of the possible solutions to my question, according to #Bob__ answer (and converting it to the code style I've used in the initial code) is as follows:
#include <iostream>
using namespace std;
bool isPrime(long int number)
{
if(number <= 1)
return false;
for(int i = 2; i <= (number / 2); i++)
if(number % i == 0)
return false;
return true;
}
int sumOfDigits(long int number)
{
int sum = 0;
while(number >= 1 && number <= 100000)
{
sum += number % 10;
number /= 10;
}
return sum;
}
long int bthPrimeAfter(int counter, long int number)
{
while(counter)
{
++number;
if(isPrime(number))
--counter;
}
return number;
}
int main()
{
long int number;
cin>>number;
int const counter = sumOfDigits(number);
cout<<bthPrimeAfter(counter, number)<<"\n";
return 0;
}
As dratenik said in their comment:
You have destroyed the value in n to produce b in the while loop. When the for loop comes around, n keeps being zero.
That's a key point to understand, sometimes we need to make a copy of a variable. One way to do that is passing it to a function by value. The function argument will be a local copy which can be changed without affecting the original one.
As an example, the main function could be written like the following:
#include <iostream>
bool is_prime(long int number);
// ^^^^^^^^ So is `n` in the OP's `main`
int sum_of_digits(long int number);
// ^^^^^^^^^^^^^^^ This is a local copy.
long int nth_prime_after(int counter, long int number);
int main()
{
long int number;
// The input validation (check if it's a number and if it's in the valid range,
// deal with errors) is left to the reader as an exercise.
std::cin >> number;
int const counter = sum_of_digits(number);
std::cout << nth_prime_after(counter, number) << '\n';
return 0;
}
The definition of sum_of_digits is straightforward.
int sum_of_digits(long int number)
{
int sum = 0;
while ( number ) // Stops when number is zero. The condition n <= 100000
{ // belongs to input validation, like n >= 0.
sum += number % 10;
number /= 10; // <- This changes only the local copy.
}
return sum;
}
About the last part (finding the nth prime after the chosen number), I'm not sure to understand what the asker is trying to do, but even if n had the correct value, for(int i = n, counter = b; counter <= 10; i++) would be just wrong. For starters, there's no reason for the condition count <= 10 or at least none that I can think of.
I'd write something like this:
long int nth_prime_after(int counter, long int number)
{
while ( counter )
{
++number;
if ( is_prime(number) )
{
--counter; // The primes aren't printed here, not even the nth.
}
}
return number; // Just return it, the printing is another function's
} // responsabilty.
A lot more could be said about the is_prime function and the overall (lack of) efficiency of this algorithm, but IMHO, it's beyond the scope of this answer.
I am implementing a c++ function to get Nth prime number using some predefined indices for time optimization purpose.
my code is :
// file prime.cpp
#include <iostream>
#include <time.h>
using namespace std;
/*
#define primeAt10000 104743
#define primeAt20000 224743
#define primeAt30000 350381
#define primeAt40000 479951
#define primeAt50000 611977
*/
int prime(int n){
int pos = 1,i = 1,temp;
if(n==0)
return 2;
/*
else if(n>50000){
i = primeAt50000;
pos = 50001;
}else if(n>40000){
i = primeAt40000;
pos = 40001;
}else if(n>30000){
i = primeAt30000;
pos = 30001;
}else if(n>20000){
i = primeAt20000;
pos = 20001;
}else if(n>10000){
i = primeAt10000;
pos = 10001;
}*/
while( i+=2 ){
temp = i/2+1;
for(int j = 3 ; j <= temp ; j+=2)
if(i%j == 0)
goto con;
if(pos++ >= n)
return i;
con :;
}
}
int main(int argc, char const *argv[]){
int index;
cin >> index;
clock_t start = clock();
cout << prime(index)<<endl;
cout << (clock()-start)/CLOCKS_PER_SEC<<"sec"<< endl;
return 0;
}
compiled with:
g++ prime.cpp -o prime.exe
I ran this code three times for inputs 9999, 19999 and 29999
1st run : 1sec 6sec 14sec
2nd run : 1sec 7sec 15sec
3rd run : 1sec 7sec 16sec
After enabling commented code again I ran three times with same inputes
1st run : 1sec 5sec 8sec
2nd run : 1sec 5sec 8sec
3rd run : 1sec 5sec 8sec
My question is :
Why this difference in taken time for each execution after second compilation while the loops are running everytime for ~1,25,000 times?
and
Why for input 19999 (~104743 looping times) it is much closer then the first 3 runs after first compilation (~224743 looping times)?
Difference in time for each 9999 interval is different because when we going towards larger numbers to check either it is prime or not it takes more time then smaller ones.
In other words directly We can say that the run-time of for-loop in prime() is increased because of larger value of variable temp.
when we checking for i = 101, the value of temp become 51 and for-loop will run approx 25 times.
while when we check for i = 10001, the value of temp become 5001 and for-loop will run for approx 2500 times.
this difference in run-time of for loop will increase your overall time complexity.
After some discussion with #JonathanLeffler I have further optimized this function to achieve fastest output for larger input values like for index 9999, 19689 and so on...
Now the complexity of my prime function is (N^2)/12 unlike before [it was (N^2)/8].
My new code is :
#include <iostream>
#include <time.h>
using namespace std;
#define primeAt10000 104743-7
#define primeAt20000 224743-7
#define primeAt30000 350381-7
#define primeAt40000 479951-7
#define primeAt50000 611977-7
bool checkPrime(int x){
int temp = x/2+1;
for(int j = 3 ; j <= temp ; j+=2)
if(x%j == 0)
return false;
return true;
}
int prime(int n){
int pos = 2,i = 0;
if(n==0)
return 2;
else if(n==1)
return 3;
else if(n>50000){
i = primeAt50000;
pos = 50000;
}else if(n>40000){
i = primeAt40000;
pos = 40000;
}else if(n>30000){
i = primeAt30000;
pos = 30000;
}else if(n>20000){
i = primeAt20000;
pos = 20000;
}else if(n>10000){
i = primeAt10000;
pos = 10000;
}
while( i+=6 ){
if(checkPrime(i-1))
if(pos++>=n)
return i-1;
if(checkPrime(i+1))
if(pos++>=n)
return i+1;
}
return 0;
}
int main()
{
int index;
cin >> index;
clock_t start = clock();
cout << prime(index)<<endl;
cout << (clock()-start)/(float)CLOCKS_PER_SEC<<"sec";
return 0;
}
Compiled with(as the advice of #NathanOliver && #JonathanLeffler) :
g++ -O3 -Wall -Werror -Wextra prime.cpp -o prime.exe
Now prime.exe taking 1.34, 4.83 and 7.20sec respectivly to inputs 9999, 19999 and 29999.
I wrote the following dp code for finding the prime factors of a number.
#include <bits/stdc++.h>
#define max 1000001
using namespace std;
vector <int> prime;
vector<bool> isprime(max,true);
vector<bool> visited(max,false);
vector<int> data(max,-1);
void dp(int n,int last)
{
if(n >= max || visited[n])
return;
visited[n] = true;
for(int i = last;i<prime.size();i++)
{
if(n*prime[i] >= max || data[n*prime[i]] != -1)
return;
data[n*prime[i]] = prime[i];
dp(n*prime[i],i);
}
}
int main()
{
isprime[1] = false;
data[1] = 1;
for(int i = 4;i<max;i += 2)
isprime[i] = false;
for(int i = 3; i*i< max;i += 2)
{
for(int j = i*i; j < max;j += i)
isprime[j] = false;
}
prime.push_back(2);
data[2] = 2;
for(int i =3;i<max;i += 2)
if(isprime[i])
{
prime.push_back(i);
data[i] = i;
}
for(int i = 0;i<prime.size();i++)
{
dp(prime[i],i);
}
cout<<"...1\n";
for(int i = 2;i<=8000;i++)
{
cout<<i<<" :- ";
int temp = i;
while(temp!= 1)
{
cout<<data[temp]<<" ";
temp = temp/data[temp];
}
cout<<endl;
}
return 0;
}
Here, last is the last index of prime number n.
But I am getting segmentation fault for this, when I change max to 10001, it runs perfectly. I'm not getting why is this happening since the data-structures used are 1-d vectors which can hold values up to 10^6 easily.
I checked your program out using GDB. The segfault is taking place at this line:
if(n*prime[i] >= max || data[n*prime[i]] != -1)
In your first ever call to DP in your for loop, where you call dp(2,0), the recursive calls eventually generate this call: dp(92692,2585).
92692 * 2585 = 239608820
This number is larger than a 32 bit integer can hold, so the r-value generated by the integer multiplication of those two numbers overflows and becomes negative. nprime[i] becomes negative, so your first condition of the above loop fails, and the second is checked. data[n * prime[i]] is accessed, and since n*prime[i] is negative, your program accesses invalid memory and segfaults. To fix this, simply change n to a long long in your parameter list and you should be fine.
void dp(long long n, int last)
I am trying to develop systematic method to came up with dynamic programming (DP) solutions - following certain steps you can came up with a valid solution to a problem.
Idea, essentially, is the following: you start from recursion, tune it to minimize number of parameters, which allows you to define problem and add memoization, after that you can easily came up with a DP solution. It turns out that it is not that simple.
One can't simply transfer recursive solution into DP.
E.g. see the subset sum PS from USACO http://train.usaco.org/usacoprob2?a=9OS8tkGfsX5&S=subset
Here is the code where my approach of turning recursion into DP is used.
#include <cstdio>
#include <iostream>
#include <cstdint>
#include <cstring>
using namespace std;
const int MAX_SUBSETSUM = (39+1)*39/4;
const int MAX_N = 39;
int memo[MAX_SUBSETSUM+1][MAX_N+1];
const int NOT_VISITED = -1;
// resembles 0-1 knapsack problem
// we need to select numbers that will go to
// the first set and those sum is totalSum/2
// so we have two sets of equal sum
int recur(int sum, int num) {
int counter = 0;
// ### 1.Base case
if(sum == 0)
return 1;
if(sum < 0 || num <= 0)
return 0;
// ### Memoization
if(memo[sum][num] != NOT_VISITED)
return memo[sum][num];
// ### 2.Recursive step
for(int nextNum = 1; nextNum < num; ++nextNum) {
if(nextNum > sum)
break;
//### 3. Make a decision
const int withNumber = recur(sum - num, nextNum);
const int withOutNumber = recur(sum, nextNum);
counter = withNumber + withOutNumber;
}
memo[sum][num] = counter;
return counter;
}
int solveDP(int subsetSum, int N) {
if(subsetSum & 1)
return 0;
int dp[MAX_SUBSETSUM+1][MAX_N+1];
memset(dp,0,sizeof(dp));
// fill in base cases
for(int i = 0; i <= N; ++i) {
// when subsetsum is 0, we have one way (we pick no nubers)
dp[0][i] = 1;
}
for(int sum =1; sum <=subsetSum; ++sum) {
for(int num = 1; num <= N; ++num) {
if(sum >= num)
dp[sum][num] = dp[sum - num][num-1]/*with num*/ + dp[sum][num-1]/*without*/;
else
dp[sum][num] = dp[sum][num-1]/*without*/;
}
}
return dp[subsetSum][N]/2; // NB!!! /2 - came up with it
}
int main() {
//freopen("preface.in", "r", stdin);
//freopen("preface.out", "w", stdout);
const int N = 7;
const int subsetSum = (N+1)*N/4;
memset(memo, NOT_VISITED, sizeof(memo));
int res = recur(subsetSum, N);
res = solveDP(subsetSum, N);
return 0;
}
In DP you have to half result(see return dp[subsetSum][N]/2;). And I found it because I got 2 versions and results differed, so it involved something like trial and error method to adjust DP to recursion.
I was able to understand why is what only after I played with DP table with paper and a pen, so I noticed that results are double counted.
That helped me.
But what to do when you got DP problem in a programming contest, you are limited in time and can't, obviously, afford to play around with DP table,
can you advise some techniques that will allow to validate results of my DP solution to make sure that it is correct.
My aim is to reduce amount of time and number of incorrect attempts.
make a simple brute force program and run a small test input to compare the
result from brute force and your DP program. "When in doubt, use brute force"
So I am a beginner in c++ programming and I was doing some problem online.
I have to calculate all the products of numbers from 999 to 100 (Eg.999*999 , 999*998 ... 800* 800 , 800 *799 ... , 100 * 100). I can easily print out these products but when I try to pass these values to a function they do not work.
Can you please look at the following code and point out anything that's wrong?
I think its got something to do with buffer but I have no idea how to fix that. Thanks.
#include <iostream>
using namespace std;
unsigned long int num,rev,temp,rem = 0,reversed = 0;
int ispalin(unsigned long int n)
{
temp=n;
while(temp!=0)
{
rem = temp%10;
reversed = reversed*10 + rem;
temp/=10;
}
if(reversed == n)
{
return 1;
}
return 0;
}
int main()
{
int maxi = 0;
for (int i =999 ; i >= 100;i--)
{
for(int j = i;j >= 100; j--)
{
rev = ispalin(i*j);
if (rev == 1)
{
if(i*j > maxi)
{
maxi = i*j;
}
}
}
}
cout<<maxi<<" This is max"<<endl;
}
reversed must be reset to zero at the beginning of every check for palindrome. The best would be to make reversed (and others) a local variable of ispalin.