minimal positive number divisible to N - algorithm

1<=N<=1000
How to find the minimal positive number, that is divisible by N, and its digit sum should be equal to N.
For example:
N:Result
1:1
10:190
And the algorithm shouldn't take more than 2 seconds.
Any ideas(Pseudocode,pascal,c++ or java) ?

Let f(len, sum, mod) be a bool, meaning we can build a number(maybe with leading zeros), that has length len+1, sum of digits equal to sum and gives mod when diving by n.
Then f(len, sum, mod) = or (f(len-1, sum-i, mod- i*10^len), for i from 0 to 9). Then you can find minimal l, that f(l, n, n) is true. After that just find first digit, then second and so on.
#define FOR(i, a, b) for(int i = a; i < b; ++i)
#define REP(i, N) FOR(i, 0, N)
#define FILL(a,v) memset(a,v,sizeof(a))
const int maxlen = 120;
const int maxn = 1000;
int st[maxlen];
int n;
bool can[maxlen][maxn+1][maxn+1];
bool was[maxlen][maxn+1][maxn+1];
bool f(int l, int s, int m)
{
m = m%n;
if(m<0)
m += n;
if(s == 0)
return (m == 0);
if(s<0)
return false;
if(l<0)
return false;
if(was[l][s][m])
return can[l][s][m];
was[l][s][m] = true;
can[l][s][m] = false;
REP(i,10)
if(f(l-1, s-i, m - st[l]*i))
{
can[l][s][m] = true;
return true;
}
return false;
}
string build(int l, int s, int m)
{
if(l<0)
return "";
m = m%n;
if(m<0)
m += n;
REP(i,10)
if(f(l-1, s-i, m - st[l]*i))
{
return char('0'+i) + build(l-1, s-i, m - st[l]*i);
}
return "";
}
int main(int argc, char** argv)
{
ios_base::sync_with_stdio(false);
cin>>n;
FILL(was, false);
st[0] = 1;
FOR(i, 1, maxlen)
st[i] = (st[i-1]*10)%n;
int l = -1;
REP(i, maxlen)
if(f(i, n, n))
{
cout<<build(i,n,n)<<endl;
break;
}
return 0;
}
NOTE that this uses ~250 mb of memory.
EDIT: I found a test where this solution runs, a bit too long. 999, takes almost 5s.

Update: I understood that the result was supposed to be between 0 and 1000, but no. With larger inputs the naïve algorithm can take a considerable amount of time. The output for 80 would be 29999998880.
You don't need a fancy algorithm. A loop that checks your condition for 1000 numbers will take less than 2 seconds on any reasonably modern computer, even in interpreted languages.
If you want to make it smart, you only need to check numbers that are multiples of N. To further restrict the search space, the remainders of N and the result have to be equal when divided by 9. This means that now you have to check only one number in every 9N.

Sure, pseudo-code, since it smells like homework :-)
def findNum (n):
testnum = n
while testnum <= 1000:
tempnum = testnum
sum = 0
while tempnum > 0:
sum = sum + (tempnum mod 10)
tempnum = int (tempnum / 10)
if sum == n:
return testnum
testnum = testnum + n
return -1
It takes about 15 thousandths of a second when translated to Python so well under your two-second threshold. It works by basically testing every multiple of N less than or equal to 1000.
The test runs through each digit in the number adding it to a sum then, if that sum matches N, it returns the number. If no number qualifies, it returns -1.
As test cases, I used:
n findNum(n) Justification
== ========== =============
1 1 1 = 1 * 1, 1 = 1
10 190 190 = 19 * 10, 10 = 1 + 9 + 0
13 247 247 = 13 * 19, 13 = 2 + 4 + 7
17 476 476 = 17 * 28, 17 = 4 + 7 + 6
99 -1 none needed
Now that only checks multiples up to 1000 as opposed to checking all numbers but checking all numbers starts to take much more than two seconds, no matter what language you use. You may be able to find a faster algorithm but I'd like to suggest something else.
You will probably not find a faster algorithm than what it would take to simply look up the values in a table. So, I would simply run a program once to generate output along the lines of:
int numberDesired[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
190, 209, 48, 247, 266, 195, 448, 476, 198, 874,
...
-1, -1};
and then just plug that into a new program so that it can use a blindingly fast lookup.
For example, you could do that with some Python like:
print "int numberDesired[] = {"
for i in range (0, 10):
s = " /* %4d-%4d */"%(i*10,i*10+9)
for j in range (0, 10):
s = "%s %d,"%(s,findNum(i*10+j))
print s
print "};"
which generates:
int numberDesired[] = {
/* 0- 9 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
/* 10- 19 */ 190, 209, 48, 247, 266, 195, 448, 476, 198, 874,
/* 20- 29 */ 3980, 399, 2398, 1679, 888, 4975, 1898, 999, 7588, 4988,
/* 30- 39 */ 39990, 8959, 17888, 42999, 28798, 57995, 29988, 37999, 59888, 49998,
/* 40- 49 */ 699880, 177899, 88998, 99889, 479996, 499995, 589996, 686999, 699888, 788998,
/* 50- 59 */ 9999950, 889899, 1989988, 2989889, 1999998, 60989995, 7979888, 5899899, 8988898, 8888999,
/* 60- 69 */ 79999980, 9998998, 19999898, 19899999, 59989888, 69999995, 67999998, 58999999, 99899888, 79899999,
:
};
That will take a lot longer than two seconds, but here's the thing: you only have to run it once, then cut and paste the table into your code. Once you have the table, it will most likely blow away any algorithmic solution.

The maximum digit sum you have to worry about is 1000. Since 1000 / 9 = ~100 This is actually not a lot, so I think the following should work:
Consider the following data structure:
entry { int r, sum, prev, lastDigit; }
Hold a queue of entry where initially you have r = 1 mod N, sum = 1, prev = -1, lastDigit = 1; r = 2 mod N, sum = 2, prev = -1, lastDigit = 2 etc.
When you extract an entry x from the queue:
y = new entry
for i = 0 to 9 do
y.r = (x.r * 10 + i) % N
y.sum = x.sum + i
y.prev = <position of x in the queue>
y.lastDigit = i
if y.r == 0 and y.sum == N
// you found your multiple: use the prev and lastDigit entries to rebuild it
if y.sum < N then
queue.add(y)
This is basically a BFS on the digits. Since the maximum sum you care about is small, this should be pretty efficient.

After thinking about it a bit, I think I have found the expected answer.
Think of it as a graph. For any number, you can make new number by multiplying that number by 10 and adding any of the digits 0-9. You will need to use BFS to reach the smallest number first.
For every node maintain sum and remainder. Using these values you can move to the adjacent nodes, also these values will help you avoid reaching useless states again and again. To print the number, you can use these values to trace your steps.
Complexity is O(n^2), in worst case table is completely filled. (See code)
Note : Code takes number of test cases first. Works under 0.3s for n<=1000.
[Edit] : Ac on spoj in 6.54s. Test files have 50 numbers.
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define F first
#define S second
#define N 1100
#define mp make_pair
queue<pair<int, int> >Q;
short sumTrace[N][N], mulTrace[N][N];
void print(int sum, int mul) {
if (sumTrace[sum][mul] == 42)return;
print(sum-sumTrace[sum][mul], mulTrace[sum][mul]);
printf("%d",sumTrace[sum][mul]);
}
void solve(int n) {
Q.push(mp(0,0));
sumTrace[0][0]=42; // any number greater than 9
while (1) {
int sum = Q.front().F;
int mul = Q.front().S;
if (sum == n && mul == 0) break;
Q.pop();
for (int i=0; i<10; i++) {
int nsum = sum+i;
if (nsum > n)break;
int nmul = (mul*10+i)%n;
if (sumTrace[nsum][nmul] == -1) {
Q.push(mp(nsum, nmul));
sumTrace[nsum][nmul] = i;
mulTrace[nsum][nmul] = mul;
}
}
}
print(n,0);
while(!Q.empty())Q.pop();
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
memset(sumTrace, -1, sizeof sumTrace);
solve(n);
printf("\n");
}
return 0;
}

Related

Counting number of possible combination to reach a sum with a die

Assume you need n steps (e.g. 100) to visit back to the start point on Monopoly,
how many combination of rolling a die to reach start point again.
The min throw count is round up (n/6), max is n (throwing 1 for n times).
n might be greater than 10000. But I can't think of any better solution other than brute force.
It depends if the order matters or not.
Let's say it doesn't. That is,
throwing 1, 2, 3 is the same as throwing 3, 2, 1. In this case this Scala snippet should work just fine.
def count(n: Int): Int = {
def count(n: Int, dots: List[Int]): Int = dots match {
case _ if n == 0 => 1
case h :: t if n > 0 => count (n - h, h :: t) + count (n, t)
case _ => 0
}
count(n, List(1, 2, 3, 4, 5, 6))
}
If the order matters than this would be the solution.
import java.math.BigInteger;
import java.util.LinkedList;
public class HexabonacciSolver {
public BigInteger solve(int n) {
LinkedList<BigInteger> lastSix = new LinkedList<>();
lastSix.add(new BigInteger("1"));
lastSix.add(new BigInteger("2"));
lastSix.add(new BigInteger("4"));
lastSix.add(new BigInteger("8"));
lastSix.add(new BigInteger("16"));
lastSix.add(new BigInteger("32"));
if (n < 7)
return lastSix.get(n - 1);
for (int i = 0; i < n - 6; i++){
lastSix.add(lastSix.get(0).add(lastSix.get(1).add(lastSix.get(2).add(lastSix.get(3).add(lastSix.get(4).add(lastSix.get(5)))))));
lastSix.removeFirst();
}
return lastSix.get(5);
}
}
Explanation: How does it work?
Let's say you want to know how many different sequences of dice rolls there are to get into the field 100 in Monopoly. You know that to get there the previous rolls had to be either 6, 5, 4, 3, 2 or 1. If you only had the number of different sequences of rolls needed to arrive to the fields 94, 95, 96, 97, 98, 99 you could just sum them up and get the solution for the field 100. This is exactly what the program does. This is very analogous to how the Fibonacci sequence is build with the difference that the next number in the sequence is calculated by summing up 6 previous numbers (hence the name "Hexabonacci")
The solution is linear O(N) in time and constant O(C) in space as we only need to store 6 last numbers of the Hexabonacci sequence.
Since the result for n=10000 has hundreds of digits the Java solution returns a BigInteger.
Let me know if you'd like to see a solution in Scala/Python/JavaScript.
Simple dynamic programming can solve this problem
#include<bits/stdc++.h>
using namespace std;
int n;
int dp[100010] = {0};
int main() {
cin >> n;
dp[0] = dp[1] = 1;
for(int i=2; i<=n ; i++){
for(int j=1; j<=6; j++)
if(i - j >= 0)
dp[i] += dp[i-j];
}
cout << dp[n] << endl;
return 0;
}
Define dp[x] be the total # of the ordered combination to achieve sum x, using 1 to 6 each step,
then dp[x] = sum (dp[x - i]) where 1 <= i <= 6 and x-i >= 0
The base case is dp[0] = dp[1] = 1
One point to note is that the number is growing fast, you may need to use long long / 64bit integer to store the result
For example, to achieve 4 steps in total,
dp(4) = dp(3) + dp(2) + dp(1) + dp(0)
= 4 + 2 + 1 + 1
= 8
Corresponding to [1,2,1], [2,1,1], [1,1,1,1], [3,1], [2,2], [1,1,2], [1,3], [4]

How to count the numbers that are divisible by their sum of digits?

Following is a question from hackerearth.
here's the link to the problem
problem!
I coded its solution in java and c but got time limit exceeded for some test cases on submission. No participant was able to solve this for all test cases. What is the most efficient solution for this?
QUESTION:
Bob likes DSD Numbers. DSD Number is a number which is divisible by its
Digit Sum in Decimal Representation.
digitSum(n) : Sum of digits of n (in Decimal Representation)
eg: n = 1234 then digitSum(n) = 1 + 2 + 3 + 4 = 10
DSD Number is number n such that n % digitSum(n) equal to 0
Bob asked Alice to tell the number of DSD Numbers in range [L,R]
inclusive.
Constraints:
1 <= test cases <= 50
1<=L<=R<=10^9
Sample Input
4
2 5
1 10
20 45
1 100
Sample Output
4
10
9
33
Code in Java:
class DSD {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out=new PrintWriter(System.out);
int t=Integer.parseInt(br.readLine());
while(t-->0){
StringTokenizer st=new StringTokenizer(br.readLine());
int L=Integer.parseInt(st.nextToken());
int R=Integer.parseInt(st.nextToken());
int count=0,sum=0,i=L,j=0;
while(i>0){
sum+=i%10;
i=i/10;
}
if(L%sum==0)
count++;
for(i=L+1;i<=R;i++){
if(i%10!=0){
sum+=1;
}
else
{
j=i;
while(j%10==0){
sum-=9;
j/=10;
}
sum+=1;
}
if(i%sum==0)
count++;
}
out.println(count);
}
out.close();
}
}
We can solve this problem by using dynamic programming.
Observation:
There will be maximum 10 digits for each number, so the maximum sum of digit for each number will be less than 100.
So, assuming that we know the sum of digit for one number, by processing digit by digit, we have four things to check:
Whether the current number is larger than the lower bound.
Whether the current number is smaller than the upper bound.
What is the mod of current number with its sum.
What is the current sum of all digits.
We come up with this function int count(int digit, boolean larger, boolean smaller, int left, int mod), and then, the dp state: dp[digit][larger][smaller][left][mod].
For each test case, time complexity is number of possible sum^3 x number of digit = 100^3*10 = 10^7.
There is 50 test cases -> 50*10^7 = 5*10^8 operations, which still be in the time limit.
Java code:
static int[][][][][] dp;
static int[][][][][] check;
static int cur = 0;
public static void main(String[] args) throws FileNotFoundException {
// PrintWriter out = new PrintWriter(new FileOutputStream(new File(
// "output.txt")));
PrintWriter out = new PrintWriter(System.out);
Scanner in = new Scanner();
int n = in.nextInt();
dp = new int[11][2][2][82][82];
check = new int[11][2][2][82][82];
for (int i = 0; i < n; i++) {
int l = in.nextInt();
int r = in.nextInt();
String L = "" + l;
String R = "" + r;
while (L.length() < R.length()) {
L = "0" + L;
}
int result = 0;
for (int j = 1; j <= 81; j++) {
cur = cur + 1;
result += count(0, 0, 0, j, 0, j, L, R);
}
out.println(result);
}
out.close();
}
public static int count(int index, int larger, int smaller, int left,
int mod, int sum, String L, String R) {
if (index == L.length()) {
if (left == 0 && mod == 0) {
return 1;
}
return 0;
}
if((L.length() - index) * 9 < left){
return 0;
}
if (check[index][larger][smaller][left][mod] == cur) {
return dp[index][larger][smaller][left][mod];
}
//System.out.println(cur);
check[index][larger][smaller][left][mod] = cur;
int x = L.charAt(index) - '0';
int y = R.charAt(index) - '0';
int result = 0;
for (int i = 0; i < 10 && i <= left; i++) {
if (x > i && larger == 0) {
continue;
}
if (y < i && smaller == 0) {
continue;
}
int nxtLarger = larger;
int nxtSmaller = smaller;
if (x < i) {
nxtLarger = 1;
}
if (y > i) {
nxtSmaller = 1;
}
int nxtMod = (mod * 10 + i) % sum;
result += count(index + 1, nxtLarger, nxtSmaller, left - i, nxtMod,
sum, L, R);
}
return dp[index][larger][smaller][left][mod] = result;
}
Update: I have submitted and passed all the test cases for this problem, (2nd person who solved this) This is the link of my submission
Let f (L, R) = "number of integers L ≤ x ≤ R where x is divisible by the sum of its digits". We define that x = 0 is not counted.
Let g (M) = "number of integers 1 ≤ x < M where x is divisible by the sum of its digits". We have f (L, R) = g (R + 1) - g (L).
Find the largest k ≥ 0 such that 10^k <= M. Find the largest a ≥ 1 such that a * 10^k <= M. All integers < M have at most 9k + (a-1) as sum of digits.
Let h (M, n) = "number of integers 1 ≤ x < M where x is divisible by n, and the sum of digits is n". g (M) is the sum of h (M, n) for 1 ≤ n ≤ 9*k + (a - 1).
Let r (a, k, n) = "number of integers a*10^k ≤ x < (a+1)*10^k where x is divisible by n, and the sum of digits is n". h (M, n) can be calculated by adding values of r (a, k, n) in an obvious way; for example:
h (1,234,000,000, n) = r (0, 9, n) + r (10, 8, n) + r (11, 8, n) + r (120, 7, n) + r (121, 7, n) + r (122, 7, n) + r (1230, 6, n) + r (1231, 6, n) + r (1232, 6, n) + r (1233, 6, n).
Let f (k, n, d, m) = "number of integers 0 ≤ x < 10^k where the sum of digits is d, and x % n = m". We can calculate r (a, k, n) using this function: The last k digits must have a digit sum of n - digitsum (a). If the whole number is divisible by n, then the last k digits must have a remainder of (- a*10^k) % n. So r (a, k, n) = f (k, n, n - digitsum(a), - (a*10^k) % n).
f (k, n, d, m) is trivial if k = 1: Only for the number d is the sum of digits equal to d, so f (1, n, d, m) is 1 if d % n = m, and 0 otherwise.
To calculate f (k+1, n, d, m) we add f (k, n, d-a, (m - a*10^k)%n) for 0 ≤ a ≤ 9. Obviously all the values f (k, n, d, m) must be stored so they are not recalculated again and again.
And that's it. How many operations: If R < 10^r, then numbers have up to 9r digits. We calculate values f (k, n, d, m) for 1 ≤ k ≤ r, for 1 ≤ n ≤ 9r, for 0 ≤ d ≤ 9r, for 0 ≤ m < n. For each of those we add 10 different numbers, so we have less than 10,000 r^4 additions. So numbers up to 10^19 are no problem.
The following approach should take about 10^7 operations per case.
Split numbers into a prefix (n/10000) and a suffix (n%10000). Once you choose a digit sum, only a little data from each of the prefix and suffix are needed to determine if the digit sum divides the number. (This is related to some things gnasher729 said, but I get a much different running time.)
For each possible digit sum d from 1 to 81,
Map prefix p to a pair (p*10000 % d, digit sum(p)).
Tally the counts in a matrix M.
Map each possible suffix s to a pair (s % d, digit sum(s)).
Tally the counts in a matrix N.
For every (a,b),
total += M[a,b] *N[-a%d,d-b]
There are about 81 * (10^5 + 10^4) steps.
The edge cases where a prefix is partially allowed (L/10000, R/10000, and 100000) can be brute-forced in about 20000 steps once.
Interesting problem. Straightforward solution would be to iterate through the numbers from L to R, calculate the sum of digits for each, and check for each whether the number is divisible by the sum of digits.
Calculating the sum of digits can be made faster obviously. The numbers xxx0, xxx1, xxx2, ..., xxx9 have digit sums n, n+1, n+2, ..., n+9. So for ten consecutive numbers almost no effort is needed to calculate the digit sum, just a modulo operation to check for divisibility.
The modulo check can be made faster. Compilers use clever tricks to divide by constants, replacing a slow division with a shift and a multiplication. You can search for how this is done, and since there are only 81 possible divisors, do at runtime what the compiler would do for constants. That should get the time down to few nanoseconds per number.
To do better: I'd make a loop checking for numbers with digit sum 1, digit sum 2, etc. As an example, assume I'm checking numbers with digit sum 17. These numbers must have a digit sum of 17, and also be multiples of 17. I take the numbers from 0000 to 9999 and for each I calculate the sum of digits, and the value modulo 17, and divide them into 37 x 17 sets where all the numbers in the set have the same digit sum and the same value modulo 17 and count the elements in each set.
Then to check the numbers from 0 to 9999: I pick the set where the digit sum is 17, and the value modulo 17 is 0 and take the element count of that set. To check numbers from 10,000 to 19,999: I pick the set where the digit sum is 16, and the value modulo 17 is 13 (because 10013 is divisible by 17), and so on.
That's just the idea. I think with a bit of cleverness that can be extended to a method that takes O (log^4 R) steps to handle all the numbers from L to R.
In the C code below, I have focused on the core portion, i.e. finding the DSD count. The code is admittedly ugly, but that's what you get when coding in a hurry.
The basic observation is that the digit sum can be simplified by tracking the digits of the number individually, reducing the digit sum determination to simple increments/decrements in each step. There are probably clever ways to accelerate the modulo computations, I could not come up with any on the double.
On my machine (Xeon E3 1270 v2, 3.5 GHz) the code below finds the count of DSDs in [1,1e9] in 3.54 seconds. I compiled with MSVC 2010 at optimization level -O2. While you stated a time limit of 1 second in an update to your question, it is not clear that this extreme case is exercised by the framework at the website you mentioned. In any event this will provide a reasonable baseline to compare other proposed solutions against.
#include <stdio.h>
#include <stdlib.h>
/* sum digits in decimal representation of x */
int digitsum (int x)
{
int sum = 0;
while (x) {
sum += x % 10;
x = x / 10;
}
return sum;
}
/* split integer into individual decimal digits. p[0]=ones, p[1]=tens, ... */
void split (int a, int *p)
{
int i = 0;
while (a) {
p[i] = a % 10;
a = a / 10;
i++;
}
}
/* return number of DSDs in [first,last] inclusive. first, last in [1,1e9] */
int count_dsd (int first, int last)
{
int num, ds, count = 0, p[10] = {0};
num = first;
split (num, p);
ds = digitsum (num);
while (p[9] < 10) {
while (p[8] < 10) {
while (p[7] < 10) {
while (p[6] < 10) {
while (p[5] < 10) {
while (p[4] < 10) {
while (p[3] < 10) {
while (p[2] < 10) {
while (p[1] < 10) {
while (p[0] < 10) {
count += ((num % ds) == 0);
if (num == last) {
return count;
}
num++;
p[0]++;
ds++;
}
p[0] = 0;
p[1]++;
ds -= 9;
}
p[1] = 0;
p[2]++;
ds -= 9;
}
p[2] = 0;
p[3]++;
ds -= 9;
}
p[3] = 0;
p[4]++;
ds -= 9;
}
p[4] = 0;
p[5]++;
ds -= 9;
}
p[5] = 0;
p[6]++;
ds -= 9;
}
p[6] = 0;
p[7]++;
ds -= 9;
}
p[7] = 0;
p[8]++;
ds -= 9;
}
p[8] = 0;
p[9]++;
ds -= 9;
}
return count;
}
int main (void)
{
int i, first, last, *count, testcases;
scanf ("%d", &testcases);
count = malloc (testcases * sizeof(count[0]));
if (!count) return EXIT_FAILURE;
for (i = 0; i < testcases; i++) {
scanf ("%d %d", &first, &last);
count[i] = count_dsd (first, last);
}
for (i = 0; i < testcases; i++) {
printf ("%d\n", count[i]);
}
free (count);
return EXIT_SUCCESS;
}
I copied the sample inputs stated in the question into a text file testdata, and when I call the executable like so:
dsd < testdata
the output is as desired:
4
10
9
33
Solution in Java
Implement a program to find out whether a number is divisible by the sum of its digits.
Display appropriate messages.
class DivisibleBySum
{
public static void main(String[] args)
{
// Implement your code here
int num = 123;
int number = num;
int sum=0;
for(;num>0;num /=10)
{
int rem = num % 10;
sum += rem;
}
if(number %sum ==0)
System.out.println(number+" is divisible by sum of its digits");
else
System.out.println(number+" is not divisible by sum of its digits");
}
}

For a given cent amount, minimize the number of coin-tubes if all tubes hold 64 but do not need to be filled

Edit: If someone could provide an explained recursive answer(a link would do) to the famous coin change problem this would help a LOT
For a given cent amount, minimize the number of coin-tubes if all tubes can hold 64 coins.
each tube can ONLY hold a single type of coin.
each tube does NOT need to be fully filled.
e.g. for american coins the amounts would be $0.01, $0.05, $0.10, $0.25, $0.50, and $1.00
6 cents could be done as 6 1cent coins in a single tube,
25 cents could be a tube with a single 25c coin or a tube with five 5c coins.
65 cents would be done as 13 5c coins, as 65 1c coins would need to use 2 tubes.
I'm attempting to write a minecraft plugin, and I am having a LOT of difficulty with this algorithm.
A lookup table is a good method.
int[] Coins = new[] { 100, 50, 25, 10, 5, 1 };
int[,] Table = new int[6,6400];
/// Calculate the number of coins of each type that minimizes the number of
/// tubes used.
int[] Tubes(int cents)
{
int[] counts = new int[Coins.Length];
if (cents >= 6400)
{
counts[0] += (cents / 6400) * 64; // number of coins in filled $1-tubes
cents %= 6400;
}
for (int i = 0; i < Coins.Length; i++)
{
int count = Table[i, cents]; // N coins in (N + 63) / 64 tubes
counts[i] += count;
cents -= count * Coins[i];
}
return cents;
}
To calculate the table, you could use this:
void CalculateTable()
{
for (int i = Coins.Length-1; i >= 0; i--)
{
int coin = Coins[i];
for (int cents = 0; cents < 6400; cents++)
{
if (i == Coins.Length-1)
{
// The 1 cent coin can't be divided further
Table[i,cents] = cents;
}
else
{
// Find the count that minimizes the number of tubes.
int n = cents / coin;
int bestTubes = -1;
int bestCount = 0;
for (int count = cents / coin; count >= 0; count--)
{
int cents1 = cents - count * coin;
int tubes = (count + 63) / 64;
// Use the algorithm from Tubes() above, to optimize the
// lesser coins.
for (int j = i+1; j < Coins.Length; j++)
{
int count1 = Table[j, cents1];
cents1 -= count1 * Coins[j];
tubes += (count1 + 63) / 64;
}
if (bestTubes == -1 || tubes < bestTubes)
{
bestTubes = tubes;
bestCount = count;
}
}
// Store the result
Table[i,cents] = bestCount;
}
}
}
}
CalculateTable runs in a few milliseconds, so you don't have to store it to disk.
Example:
Tubes(3149) -> [ 31, 0, 0, 0, 0, 49]
Tubes (3150) -> [ 0, 63, 0, 0, 0, 0]
Tubes (31500) -> [315, 0, 0, 0, 0, 0]
The numbers mean the number of coins. N coins could be put into (N + 63)/64 tubes.
something like this:
a[0] = 100; //cents
a[1] = 50; a[2] = 25; a[3] = 10; a[4] = 5; a[5] = 1;
cnt[6]; //array to store how much coins of type i you use;
void rec(sum_left, p /* position in a array */) {
if ( p == 5 ) {
cnt[5] = sum_left;
//count how many tubes are used by cnt array, update current answer if neccessary;
return;
}
for ( int i = 0; i <= sum_left/a[p]; i++ )
//take i coins of type a[p]
rec(sum_left - i*a[i], p+1);
}
int main() {
rec(sum, 0);
}
Here is a recursive, heuristic and greedy algorithm.
In the array T, each T[i] holds an array of 6 integers.
If the given sum is 65 then you call tubes(65) and then print T[65].
coins[1..6] = {1, 5, 10, 25, 50, 100}
tubes(sum)
if sum < coins[1]
return
for i = 1 to 6
tubes(sum - coins[i])
best-tubes[1..6] = {64, 64, 64, 64, 64, 64}
for i = 1 to 6
if sum - coins[i] >= 0
current-tubes[1..6] = copy of T[sum - coins[i]]
if current-tubes[i] < 64
current-tubes[i] += 1
if current-tubes is better than best-tubes*
best-tubes = current-tubes
T[sum] = best-tubes
To vastly improve the running time, you can check if the current T[sum] has already been evaluated. Adding this check completes the approach called dynamic programming.
*current-tubes is better than best-tubes is using less tubes, or using the same number of tubes with less coins or using the same number of tubes but tubes that hold larger values. This is the greedy in action part.

Better Solution to Project Euler #36?

Project Euler problem 36 states:
The decimal number, 585 = 1001001001 (binary), is palindromic in both bases.
Find the sum of all numbers, less than one million, which are palindromic in base 10 and base 2.
(Please note that the palindromic number, in either base, may not include leading zeros.)
There is already a solution to this on stack overflow, but I want a more efficient solution.
For example, since the palindrome cannot have leading 0's, no even numbers need to be checked, only odd numbers for which the last bit in binary is a 1. This simple observation already speeds up the brute force "check every number in the range" by a factor of 2.
But I would like to be more clever than that. Ideally, I would like an algorithm with running time proportional to the number of numbers in the sum. I don't think it's possible to do better than that. But maybe that is not possible. Could we for example, generate all palindromic decimal numbers less than one million in time proportional to the number of decimal numbers satisfying that property? (I think the answer is yes).
What is the most efficient algorithm to solve this palindrome sum problem? I would like to consider run-times parameterized by N: the size of the range of numbers (in this case 1 million), D: the set of decimal palindromes in the range, and B: the set of binary palindromes in the range. I hope for a run-time that is o(N) + O( |D intersect B| ), or failing that, O(min(|D|, |B|))
Note: The sequences of binary and decimal palindromes are well known.
e.g. binary palindromes < 100: 0, 1, 3, 5, 7, 9, 15, 17, 21, 27, 31, 33, 45, 51, 63, 65, 73, 85, 93, 99
. . .decimal palindromes < 100:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99,
palindromes in both bases: 0, 1, 3, 5, 7, 9, 33, 99
The binary representations of 33 and 99 are 10001 and 1100011 respectively.
The next number which is a palindrome in both is 585 = 1001001001.
The number of palindromes in base b of length 2*k is (b-1)*b^(k-1), as is the number of palindromes of length 2*k-1. So the number of palindromes not exceeding N in any base is O(sqrt(N))¹. So if you generate all palindromes (not exceeding N) in one base and check if they are also palindromes in the other base, you have an O(sqrt(N)*log(N)) algorithm (the log factor comes from the palindrome check). That's o(N), but I don't know yet if it's also O(|D intersect B|).
It's not O(|D intersect B|) :( There are only 32 numbers up to 1010 which are palindromic in both bases. I don't see any pattern that would allow constructing only those.
¹ If N has d digits (in base b), the number of palindromes not exceeding N is between the number of palindromes having at most d-1 digits and the number of palindromes having at most d digits (both limits inclusive). There are (b-1)*b^(k-1) numbers having exactly k digits (in base b), of which (b-1)*b^(floor((k-1)/2))) are palindromes. Summing gives the number of base-b palindromes with at most k digits as either 2*(b^(k/2)-1) (if k is even) or (b-1)*b^((k-1)/2) + 2*(b^((k-1)/2)-1) (if k is odd). Hence, give or take a factor of 2*b, the number of palindromes with at most d digits is b^(d/2). Thus the number of palindromes not exceeding N is roughly N^0.5, with a factor bounded by a multiple of the base considered.
Consider that there are only about 2000 decimal palindromes between 1 and 1000000. From 1 to 999, you can string the number and its reverse together, both with and without duplicating the "middle" digit (the last digit of the left part). For each of those, you check whether it's also a binary palindrome, and if it is, it's part of the sum.
(not an answer to your question but a cute recursive bit-fiddling solution to Project Euler 36)
This may not be the most efficient algorithm but I like how it looks like. I wrote it after reading Daniel Fischer's answer, suggesting to generate all palindromes in one base and then checking in the other base if it's a palindrome too.
In 18 lines of code (including the brackets) it generates all the palindromes in base 2 and then checks if they're also palindrome in base 10.
Takes about 6 ms on my system.
This can probably be optimized (too many bitshifting operation to my taste, there's probably quite some unnecessary junk here) and there may be a better algo, but I "like" (+) the look of my code ; )
#Test
public void testProjectEuler36() {
final int v = rec(1, 1);
assertEquals( 872187, v );
}
public static int rec( final int n, final int z ) {
if ( n > 1000000 )
return 0;
if ( z % 2 == 0 ) {
final int l = n << 1 & -1 << z / 2 + 1;
final int r = n & -1 >>> 32 - z / 2;
return v(n) + rec( l | 1 << z / 2 | r, z + 1 ) + rec( l | r, z + 1 );
} else
return v(n) + rec( n << 1 & -1 << z / 2 + 1 | n & -1 >>> 31 - z / 2, z + 1 );
}
public static int v( final int n ) {
final String s = "" + n;
boolean ok = true;
for ( int j = s.length(), i = j / 2 - 1; i >= 0 && ok; i--)
ok = s.charAt(i) == s.charAt(j-(i+1));
return ok ? n : 0;
}
My first assumptions were entirely wrong, so I've fixed them up. I've provided two algorithms, one iterative and one recursive. They're obviously nowhere near as impressive and efficient as user988052's, but they're definitely easier to read! The first algorithm is iterative and has a runtime of 9ms. The second algorithm is recursive and has a runtime of 16ms. Although the second solution is cleaner, the recursive calls might be slowing it down.
First Algorithm (9ms):
/** Given half a palindrome, construct the rest of the palindrome with
* an optional string inserted in the middle. The returned string is
* only guaranteed to be a palindrome if 'mid' is empty or a palindrome. */
public static String getPalindrome(String bin_part, String mid) {
return bin_part + mid + (new StringBuilder(bin_part)).reverse();
}
/** Check if the specified string is a palindrome. */
public static boolean isPalindrome(String p) {
for (int i=0; i<p.length()/2; i++)
if (p.charAt(i) != p.charAt(p.length()-1-i))
return false;
return true;
}
public static void main(String[] args) {
String[] mids = {"0","1"};
long total = 0;
boolean longDone = false; // have the numbers with extra digits been tested
long start = System.currentTimeMillis();
for (long i=0; i<1000; i++) {
String bin_part = Long.toBinaryString(i);
String bin = getPalindrome(bin_part, "");
long dec = Long.valueOf(bin, 2);
if (dec >= 1000000) break; // totally done
if (isPalindrome(Long.toString(dec)))
total += dec;
if (!longDone) {
for (int m=0; m<mids.length; m++) {
bin = getPalindrome(bin_part, mids[m]);
dec = Long.valueOf(bin, 2);
if (dec >= 1000000) {
longDone = true;
break;
}
if (isPalindrome(Long.toString(dec)))
total += dec;
}
}
}
long end = System.currentTimeMillis();
System.out.println("Total: " + total + " in " + (end-start) + " ms");
}
Second Algorithm (16ms)
public long total = 0;
public long max_value = 1000000;
public long runtime = -1;
public static boolean isPalindrome(String s) {
for (int i=0; i<s.length()/2; i++)
if (s.charAt(i) != s.charAt(s.length()-1-i))
return false;
return true;
}
public void gen(String bin, boolean done) {
if (done) { // generated a valid binary number
// check current value and add to total if possible
long val = Long.valueOf(bin, 2);
if (val >= max_value)
return;
if (isPalindrome(Long.toString(val))) {
total += val;
}
// generate next value
gen('1' + bin + '1', true);
gen('0' + bin + '0', false);
} else { // generated invalid binary number (contains leading and trailing zero)
if (Long.valueOf('1' + bin + '1', 2) < max_value) {
gen('1' + bin + '1', true);
gen('0' + bin + '0', false);
}
}
}
public void start() {
total = 0;
runtime = -1;
long start = System.currentTimeMillis();
gen("",false);
gen("1",true);
gen("0",false);
long end = System.currentTimeMillis();
runtime = end - start;
}
public static void main(String[] args) {
Palindromes2 p = new Palindromes2();
p.start();
System.out.println("Total: " + p.total + " in " + p.runtime + " ms.");
}
Here is the best Python Implementation to solve this problem :
sum = 0
for i in range(1000000):
bina = int(str(bin(i)).replace('0b',''))
if(i==int(str(i)[::-1]))or(bina==int(str(bina)[::-1])):
#print("i : "+str(i))
#print("bina : "+str(bina))
sum+=i
print("Sum of numbers : ",sum)

Unlucky Numbers

Unlucky Numbers (NOT HOMEWORK)
There are few numbers considered to be unlucky(It contains only 4 and 7. ). Our goal is to find count of such numbers in the range of positive integers a and b.
For Example:
Input : a = 10 b = 20
Output : 0
Input : a = 30 b = 50
Output : 2 (44, 47)
Below is the Code I tried out using a static array approach, wherein I calculate all possible unlucky numbers for a 32-bit integer initially. This is done in O(n) and later a sequential scan helps obtain the count which is again an O(n) operation. Is there a better approach to solve this without the help of a static array ?
#define MAX_UNLUCKY 1022
static int unlucky[MAX_UNLUCKY];
int main(int argc, char **argv) {
int i, j, k;
int a, b, factor;
printf("Enter the numbers : \n");
scanf("%d",&a);
scanf("%d",&b);
unlucky[0] = 4;
unlucky[1] = 7;
factor = 10;
k = 1;
for(i = 2; i < MAX_UNLUCKY; ++i)
unlucky[i] = unlucky[(i >> 1) - 1]*factor + unlucky[k ^= 1];
for (i = 0; i < MAX_UNLUCKY;++i)
if (unlucky[i] > a) break;
for (k = i; k < MAX_UNLUCKY;++k) {
if (unlucky[k] > b) break;
printf("Unlukcy numbers = %d\n", unlucky[k]);
}
printf ("Total Number of Unlucky numbers in this range is %d\n", k-i);
return (0);
}
Consider the following:
How many numbers are there between
0x100 and 0x111?
100,101,110,111 ( 4 = 0x111 - 0x100 + 1 )
That's exactly how many unlucky numbers there are between 744 and 777 (744,747,774,777).
Now:
700 and 800 have the same number of unlucky numbers between them as 744 and 777.
744 is the smallest unlucky number greater than 700 and 777 is the greatest unlucky number smaller than 800.
No need to generate numbers, just substraction.
For cases like a = 10, b = 800, first find your number for 10-100 and then 100-800 (because you'll be counting some numbers twice):
For 10-100:
a = 44
b = 77
0x11 - 0x00 = 3 + 1 = 4 ( 44,47,74,77 )
For 100-800:
a = 444
b = 777
0x111 - 0x000 = 7 + 1 = 8 ( 444, 447, 474, 477, 744, 747, 774, 777 )
So between 10 and 800: 4+8 = 12 numbers, which is also correct.
This is also O(1) time & space if you find the auxiliary numbers efficiently, which shouldn't be too hard...

Resources