How to make this algorithm faster? [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am trying to come up with the following algorithm:
The input is unsigned integer number.
The output is the size of the array of unordered pairs of unsigned integers, which, when multiplied, give a number less then or equal to the input.
I have one naive implementation working, but it is way too slow for my purpose (compl. O(n^2), please correct me if I am wrong). My question is: how to make it faster?
#include <iostream>
using namespace std;
bool notInYet(int t[][1], int mi, int ma, int m) {
bool val = true;
for(int i = 0; i < m; i++)
if(t[i][0] == mi && t[i][1] == ma)
val = false;
return val;
}
int main() {
int n, m;
int t[100000][1];
cin >> n;
m = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j*i <= n && j <= i; j++) {
if(notInYet(t, j, i, m)) {
t[m][0] = j;
t[m][1] = i;
//cout << "t[" << m << "] = (" << t[m][0] << ", " << t[m][1] << ")" << endl;
m++;
}
}
}
cout << m << endl;
return 0;
}

I think it should be something like that - pseudocode:
int counter = 0;
for int i = 1 to sqrt(input), i++ {
if (input % i == 0) counter++;
}
counter is an answer if you need unique pairs, otherwise you need to multiply it by 2 (and sub 1 if input % sqrt(input) == 0)

If I'm reading correctly #jauser's algorithm doesn't get what you want.
If the target is 5, then the pairs are (1,1)(1,2)(1,3)(1,4)(1,5)(2,2). So the answer is 6. His algorithm will produce 1 because 5 mod 1 == 0, but not mod 2.
In general, if the target is n, then you know (1,k) is a counted pair for all k from 1 to n. There are n - 1 + 1 = n of these. Now you have (2,k) for k from 2 to floor(n/2) (skip 1 because your pairs are unordered). There are n/2-2+1 of these. Continue this through (j,k) for j= floor(sqrt(n)). Putting this is pseudocode
count = 0;
for j in 1 .. floor(sqrt(n))
count += floor(n / j) - j + 1;
Maybe there is even some clever series solution that gets this to a constant time calculation.
Am I missing something in the problem?

Well, you are spending a lot of time effectively calculating the following per i:
j= n/i;
So if you just do that you reduce the complexity to O(n). You can halve it also since the list will contain both (i, j) and (j, i) when i!=j, but that won't reduce the overall complexity.

Related

Compiler optimization on the traveling salesman problem

I am playing with the travelling salesman problem and am looking at the version where:
the towns are points in 2d space and there are paths from every town to all others and the lengths are the distances between the points. So it's very easy to implement the naive solution where you check all permutations of n points and calculate the length of the path.
I've found however that for n >= 10 the compiler does some magic and prints a value that is certainly not the actual shortest path. I compile with the Microsoft visual studio compiler in release mode with the default settings. For values (10,30) it thinks for 30 seconds and then returns some number that seems like it could be correct but it is not (I check in different ways). And for n > 40 it calculates a result immediately and is always 2.14748e+09.
I am looking for an explanation to what does the compiler do in the different situations (the (10,30) case is really interesting). And an example where these optimizations are more useful than the program just spinning to the end of the world.
vector<pair<int,int>> points;
void min_len()
{
// n is a global variable with the number of points(towns)
double min = INT_MAX;
// there are n! permutations of n elements
for (auto j = 0; j < factorial(n); ++j)
{
double sum = 0;
for (auto i = 0; i < n - 1; ++i)
{
sum += distance_points(points[i], points[i + 1]);
}
if (sum < min)
{
min = sum;
s_path = points;
}
next_permutation(points.begin(), points.end());
}
for (auto i = 0; i < n; ++i)
{
cout << s_path[i].first << " " << s_path[i].second << endl;
}
cout << min << endl;
}
unsigned int factorial(unsigned int n)
{
int res = 1, i;
for (i = 2; i <= n; i++)
res *= i;
return res;
}
Your factorial function is overflowing. Try replacing it with one returning int64_t and see your code taking 3 years to terminate for n > 20.
constexpr uint64_t factorial(unsigned int n) {
return n ? n * factorial(n-1) : 1;
}
Also, you don't need to calculate this at all. The std::next_permutation function returns 0 when all permutations have occured (starting from sorted position).

Incorrect mathematical results calculating power series [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
#include <iostream>
#include <cmath>
using namespace std ;
int main ()
{
int n, sum=0 ;
cout<< "Input number of terms: " ;
cin>> n ;
for (int i=1; i<=n; i++)
{
int k = pow(10, i) - 1 ;
cout << k ;
if(i < n)
{
cout<< " + " ;
}
sum += k ;
}
cout << "\nThe sum of the series = " << sum ;
{int m;cin>>m;}
return 0 ;
}
every time I run this code it gives me weird output like
9 + 98 + 999 + 9998 + ...
it subtracts some Ks from 2 !!
The rule is mathematically right and there is no syntax errors.
Is it the way of declaring k inside the loop or it's an compiler error ?
So, what's wrong here?
Here is the for loop without using the pow function:
int power = 10;
for (int i = 1; i < n-1; ++i)
{
const int k = power - 1 ;
cout << k;
if(i < n)
{
cout<< " + " ;
}
sum += k;
power *= 10; // This is important.
}
This should be more accurate than using pow because there is no conversions between integer and floating point.
Also, you may want to try using the series from 0 .. (n-1).
I think the best thing to do is to create your own power function because pow() is not working that way before when I used it. Kinda like this one
int pow_num(int base_num, int exp_num)
{
int result = 1;
for(int i = 0; exp_num > i; ++i)
{
result = result * base_num;
}
return (result);
}

find number of combinations where XOR of each combination is equal to a given number [duplicate]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
Given an array, arr, of length n, find how many subsets of arr there are such that XOR(^) of those subsets is equal to a given number, ans.
I have this dp approach but is there a way to improve its time complexity. ans is always less than 1024.
Here ans is the no. such that XOR(^) of the subsets is equal to it.
arr[n] contains all the numbers
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(i = 1; i <= n; i++){
for(j = 0; j < 1024; j++) {
dp[i][j] = (dp[i-1][j] + dp[i-1][j^arr[i]]);
}
}
cout << (dp[n][ans]);
From user3386109's comment, building on top of your code:
/* Warning: Untested */
int counts[1024] = {0}, ways[1024];
for(int i = 1; i <= n; ++i) counts[ arr[i] ] += 1;
for(int i = 0; i <= 1024; ++i) {
const int z = counts[i];
// Look for overflow here
ways[i] = z == 0 ?
0 :
(int)(1U << (z-1));
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(i = 1; i <= 1024; i++){
for(j = 0; j < 1024; j++) {
// Check for overflow
const int howmany = ways[i] * dp[i-1][j];
dp[i][j] += howmany;
dp[i][j^i] += howmany;
}
}
cout << (dp[1024][ans]);
For calculating odd_ and even_, you can also use the following:
nc0+nc2+... =
nc1+nc3... =
2n-1
Because number of ways to select odd items = number of ways to reject odd items = number of ways to select even numbers
You can also optimize the space by keeping just 2 columns of dp arrays and reusing them as dp[i-2][x] are discarded.
The Idea behind dynamic programming is, to (1) never compute the same result twice and (2) only compute results at demand and not precompute the whole thing as you do it.
So there is a solution needed for solve(arr, n, ans) with ans < 1024, n < 1000000 and arr = array[n]. The idea of having dp[n][ans] holding the number of results is reasonable, so dp size is needed as dp = array[n+1][1024]. What we need is a way to distinguish between not yet computed results and available results. So memset(dp, -1, sizeof(dp)) and then as you already did dp[0][0] = 1
solve(arr, n, ans):
if (dp[n][ans] == -1)
if (n == 0) // and ans != 0 since that was initialized already
dp[n][ans] = 0
else
// combine results with current and without current array element
dp[n][ans] = solve(arr + 1, n - 1, ans) + solve(arr + 1, n - 1, ans XOR arr[0])
return dp[n][ans]
The advantage is, that your dp array is only partially computed on the way to your solution, so this might save some time.
Depending on the stack size and n, it might be necessary to translate this from a recursive to an iterative solution

Given an array of length n, find number of subsets where XOR of a subset is equal to a given number [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
Given an array, arr, of length n, find how many subsets of arr there are such that XOR(^) of those subsets is equal to a given number, ans.
I have this dp approach but is there a way to improve its time complexity. ans is always less than 1024.
Here ans is the no. such that XOR(^) of the subsets is equal to it.
arr[n] contains all the numbers
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(i = 1; i <= n; i++){
for(j = 0; j < 1024; j++) {
dp[i][j] = (dp[i-1][j] + dp[i-1][j^arr[i]]);
}
}
cout << (dp[n][ans]);
From user3386109's comment, building on top of your code:
/* Warning: Untested */
int counts[1024] = {0}, ways[1024];
for(int i = 1; i <= n; ++i) counts[ arr[i] ] += 1;
for(int i = 0; i <= 1024; ++i) {
const int z = counts[i];
// Look for overflow here
ways[i] = z == 0 ?
0 :
(int)(1U << (z-1));
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(i = 1; i <= 1024; i++){
for(j = 0; j < 1024; j++) {
// Check for overflow
const int howmany = ways[i] * dp[i-1][j];
dp[i][j] += howmany;
dp[i][j^i] += howmany;
}
}
cout << (dp[1024][ans]);
For calculating odd_ and even_, you can also use the following:
nc0+nc2+... =
nc1+nc3... =
2n-1
Because number of ways to select odd items = number of ways to reject odd items = number of ways to select even numbers
You can also optimize the space by keeping just 2 columns of dp arrays and reusing them as dp[i-2][x] are discarded.
The Idea behind dynamic programming is, to (1) never compute the same result twice and (2) only compute results at demand and not precompute the whole thing as you do it.
So there is a solution needed for solve(arr, n, ans) with ans < 1024, n < 1000000 and arr = array[n]. The idea of having dp[n][ans] holding the number of results is reasonable, so dp size is needed as dp = array[n+1][1024]. What we need is a way to distinguish between not yet computed results and available results. So memset(dp, -1, sizeof(dp)) and then as you already did dp[0][0] = 1
solve(arr, n, ans):
if (dp[n][ans] == -1)
if (n == 0) // and ans != 0 since that was initialized already
dp[n][ans] = 0
else
// combine results with current and without current array element
dp[n][ans] = solve(arr + 1, n - 1, ans) + solve(arr + 1, n - 1, ans XOR arr[0])
return dp[n][ans]
The advantage is, that your dp array is only partially computed on the way to your solution, so this might save some time.
Depending on the stack size and n, it might be necessary to translate this from a recursive to an iterative solution

C++ program to find the largest palindrome which is product of two two digit numbers [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have seen this, but this is not what I am looking for.
The problem is same that is to find the largest palindrome which is the product of two three digit numbers.
Since my program was not working so I made a little change, instead of finding the largest palindrome which is the product of two three digit numbers I have written the program to find the largest palindrome which is the product of two two digit numbers.
Kindly see the program:
#include <iostream>
using namespace std;
int main() {
int i, j, n, s, m, w;
for (i = 99; i > 9; i--) {
for (j = 99; j > 9; j--)
n = i * j;
s = n;
while (n != 0) {
w = 0;
m = n % 10;
w = w * 10 + m;
n = n / 10;
}
if (s == w)
cout << s << endl;
break;
}
return 0;
}
The problem with this program is that it is neither showing any error nor giving any result.
So kindly help me to find the problem in my program.
Right now you are missing the curly braces for the j-loop. The current code is doing 99! * i.
Then you would have to focus on storing the largest palindrome value instead of just printing all those values to the screen (this is considering your implementation, it is not the most efficient one by any means).
Some modified version of your code:
#include <iostream>
using namespace std;
int main() {
int max_product = 0;
for (int i = 99; i > 9; i--) {
for (int j = i; j > 9; j--) {
int product = i * j;
if (product < max_product)
break;
int number = product;
int reverse = 0;
while (number != 0) {
reverse = reverse * 10 + number % 10;
number /= 10;
}
if (product == reverse && product > max_product) {
max_product = product;
}
}
}
cout << "Solution: " << max_product << endl;
return 0;
}
You have various problems:
Need one more pair of {, }. After the for-loop of j. The only instruction the for-loop of j is executing is: n = i * j; with the braces the rest of the instruction (testing if it's a palindrome) are out of the loop.
the variable w the reverse of the number to test for palindrome is reset his value to 0 in every execution of while (n != 0) loop resulting in incorrect reverse value (and never find the palindrome).
The max palindrome product of 2 two digits number don't have to be the first one found with this 2 for-loop, eg: suppose that there is 2 valid solutions i = 98, j = 2 and i = 70, j = 65 in this case i*j would be in first solution = 196 in the second = 4550 and when you found the first you could not stop the search. In your code using the break don't do what I think you are waiting for (stop the search), only stop the search with the actual i value.
Some notes about the modified code:
The two for-loop don't need to be from 99..9, in this case you are testing a lot of product two times (eg: 98*99, are testing when i == 98 and j == 99 and i == 99 and j == 98), you could restrict j to be always less or equal to i.
Using max_product to maintain the maximum palindrome product found. And use that info in the inner loop (if (product < max_product)) for early exit when no better solution could be found.