Based on WolframH's answer, I tried the problem for the sample inputs in C++ and it seems to work. I also tried the phython solution, which worked fine with the sample inputs. What comes interesting is, when I increased the input to a bit bigger numbers (i.e., 3 and 18), both solutions I have in C++ and in phython hang for indeterminate time.
What has gone wrong?
Very coincidentally I just happened to go through my Dynamic Programming notes yesterday night, and read about the Weighted Independent Set Problem. Aha! We are doing far too much work than we are supposed to! In:
#include <math.h>
#include <iomanip>
#include <iostream>
using namespace std;
void get_tight_number(int base_max, int length)
{
double result = 0;
int _tight_numbers = 0;
double total = pow(base_max + 1, length);
for (int i = 0; i <= base_max; ++i)
{
_tight_numbers += get_tight_number_help(base_max, length, i);
}
result = 100 * _tight_numbers / total;
cout << fixed << setprecision(5) << result << "\n";
}
int get_tight_number_help(int base_max, int length, int endwith)
{
cout << "Length: " << length << "endwith: " << endwith << endl;
if (length < 1 || endwith < 0 || endwith > base_max)
return 0;
if (length == 1)
{
return 1;
} else
{
return get_tight_number_help(base_max, length - 1, endwith)
+ get_tight_number_help(base_max, length - 1, endwith + 1)
+ get_tight_number_help(base_max, length - 1, endwith - 1);
}
}
int main()
{
get_tight_number(8, 7);
return 0;
}
With bunch of prints and correct result 0.10130. If I do grep "endwith:" | wc -l I get 7719, which means, for this input, the helper function was called more than 7000 times! To just have an idea how many times it is called on other inputs, I got:
Input #
8, 8 22254
8, 6 2682
8, 5 933
not very good... We are doing too much recalculation. Instead I put together the bottom up solution for the reference array:
int** tight_number_bottom_up(int base_max, int length)
{
int** result = new int*[base_max + 1];
for (int i = 0; i < base_max + 1; ++i)
{
result[i] = new int[length];
}
//Ends with i, i.e., looping over them
for (int j = 0; j < length + 1; ++j)
{
for (int i = 0; i < base_max + 1; ++i)
{
if (j == 0)
{
result[i][j] = 0;
} else if (j == 1)
{
result[i][j] = 1;
} else
{
int bigger = i == base_max ? 0 : result[i + 1][j - 1];
cout << "bigger: " << bigger << endl;
int smaller = i == 0 ? 0 : result[i - 1][j - 1];
cout << "smaller: " << smaller << endl;
result[i][j] = result[i][j - 1] + bigger + smaller;
}
}
}
return result;
}
I am sure that the number of iterations in forming the bottom up table is maximum (base_max + 1) * (length + 1), happy that I finished writing and happy that it gives the correct results.
Follow-up question (if you are still with me)
double seems to be not enough for inputs like 9, 100 or even 9, 50, what can I do to make a "long"er double?
00010. Did you miss that case, or are you including it?00000is tight for k=2, n=5, since if you pick any 2 adjacent digits (say digit #2 and digit #3), they are both 0, so they have a difference of 0 which is <= 1.02or the substring20. Also: one powerful technique for solving problems like this is called generating functions: en.wikipedia.org/wiki/Generating_function