So I want to solve an exercise in C or in SML but I just can't come up with an algorithm that does so. Firstly I will write the exercise and then the problems I'm having with it so you can help me a bit.
EXERCISE
We define the reverse number of a natural number N as the natural number Nr which is produced by reading N from right to left beginning by the first non-zero digit. For example if N = 4236 then Nr = 6324 and if N = 5400 then Nr = 45.
So given any natural number G (1≤G≤10^100000) write a program in C that tests if G can occur by the sum of a natural number N and its reverse Nr. If there is such a number then the program must return this N. If there isn't then the program must return 0. The input number G will be given through a txt file consisted only by 1 line.
For example, using C, if number1.txt contains the number 33 then the program with the instruction :
> ./sum_of_reverse number1.txt
could return for example 12, because 12+21 = 33 or 30 because 30 + 3 = 33. If number1.txt contains the number 42 then the program will return 0.
Now in ML if number1.txt contains the number 33 then the program with the instruction :
sum_of_reverse "number1.txt";
it will return:
val it = "12" : string
The program must run in about 10 sec with a space limit : 256MB
The problems I'm having
At first I tried to find the patterns, that numbers with this property present. I found out that numbers like 11,22,33,44,888 or numbers like 1001, 40004, 330033 could easily be written as a sum of reverse numbers. But then I found out that these numbers seem endless because of numbers for example 14443 = 7676 + 6767 or 115950 = 36987 + 78963.
Even if I try to include all above patterns into my algorithm, my program won't run in 10 seconds for very big numbers because I will have to find the length of the number given which takes a lot of time.
Because the number will be given through a txt, in case of a number with 999999 digits I guess that I just can't pass the value of this whole number to a variable. The same with the result. I assume that you are going to save it to a txt first and then print it??
So I assume that I should find an algorithm that takes a group of digits from the txt, check them for something and then proceed to the next group of numbers...?
Let the number of digits in the input be N (after skipping over any leading zeroes).
Then - if my analysis below is correct - the algorithm requires only ≈ N bytes of space and a single loop which runs ≈ N/2 times.
No special "big number" routines or recursive functions are required.
Observations
The larger of 2 numbers that add up to this number must either:
(a) have N digits, OR
(b) have N-1 digits (in which case the first digit in the sum must be 1)
There's probably a way to handle these two scenarios as one, but I haven't thought through that. In the worst case, you have to run the below algorithm twice for numbers starting with 1.
Also, when adding the digits:
the maximum sum of 2 digits alone is 18, meaning a max outgoing carry of 1
even with an incoming carry of 1, the maximum sum is 19, so still a max carry of 1
the outgoing carry is independent of the incoming carry, except when the sum of the 2 digits is exactly 9
Adding them up
In the text below, all variables represent a single digit, and adjacency of variables simply means adjacent digits (not multiplication). The ⊕ operator denotes the sum modulo 10. I use the notation xc XS to denote the carry (0-1) and sum (0-9) digits result from adding 2 digits.
Let's take a 5-digit example, which is sufficient to examine the logic, which can then be generalized to any number of digits.
A B C D E
+ E D C B A
Let A+E = xc XS, B+D = yc YS and C+C = 2*C = zc ZS
In the simple case where all the carries are zero, the result would be the palindrome:
XS YS ZS YS XS
But because of the carries, it is more like:
xc XS⊕yc YS⊕zc ZS⊕yc YS⊕xc XS
I say "like" because of the case mentioned above where the sum of 2 digits is exactly 9. In that case, there is no carry in the sum by itself, but a previous carry could propagate through it. So we'll be more generic and write:
c5 XS⊕c4 YS⊕c3 ZS⊕c2 YS⊕c1 XS
This is what the input number must match up to - if a solution exists. If not, we'll find something that doesn't match and exit.
(Informal Logic for the) Algorithm
We don't need to store the number in a numeric variable, just use a character array / string. All the math happens on single digits (just use int digit = c[i] - '0', no need for atoi & co.)
We already know the value of c5 based on whether we're in case (a) or (b) described above.
Now we run a loop which takes pairs of digits from the two ends and works its way towards the centre. Let's call the two digits being compared in the current iteration H and L.
So the loop will compare:
XS⊕c4 and XS
YS⊕c3 and YS⊕c1
etc.
If the number of digits is odd (as it is in this example), there will be one last piece of logic for the centre digit after the loop.
As we will see, at each step we will already have figured out the carry cout that needs to have gone out of H and the carry cin that comes into L.
(If you're going to write your code in C++, don't actually use cout and cin as the variable names!)
Initially, we know that cout = c5 and cin = 0, and quite clearly XS = L directly (use L⊖cin in general).
Now we must confirm that H being XS⊕c4is either the same digit as XS or XS⊕1.
If not, there is no solution - exit.
But if it is, so far so good, and we can calculate c4 = H⊖L. Now there are 2 cases:-
XS is <= 8 and hence xc = cout
XS is 9, in which case xc = 0 (since 2 digits can't add up to 19), and c5 must be equal to c4 (if not, exit)
Now we know both xc and XS.
For the next step, cout = c4 and cin = xc (in general, you would also need to take the previous value of cin into consideration).
Now when comparing YS⊕c3 and YS⊕c1, we already know c1 = cin and can compute YS = L⊖c1.
The rest of the logic then follows as before.
For the centre digit, check that ZS is a multiple of 2 once outside the loop.
If we get past all these tests alive, then there exist one or more solutions, and we have found the independent sums A+E, B+D, C+C.
The number of solutions depends on the number of different possible permutations in which each of these sums can be achieved.
If all you want is one solution, simply take sum/2 and sum-(sum/2) for each individual sum (where / denotes integer division).
Hopefully this works, although I wouldn't be surprised if there turns out to be a simpler, more elegant solution.
Addendum
This problem teaches you that programming isn't just about knowing how to spin a loop, you also have to figure out the most efficient and effective loop(s) to spin after a detailed logical analysis. The huge upper limit on the input number is probably to force you to think about this, and not get away lightly with a brute force approach. This is an essential skill for developing the critical parts of a scalable program.
I think you should deal with your numbers as C strings. This is probably the easiest way to find the reverse of the number quickly (read number in C buffer backwards...) Then, the fun part is writing a "Big Number" math routines for adding. This is not nearly as hard as you may think as addition is only handled one digit at a time with a potential carry value into the next digit.
Then, for a first pass, start at 0 and see if G is its reverse. Then 0+1 and G-1, then... keep looping until G/2 and G/2. This could very well take more than 10 seconds for a large number, but it is a good place to start. (note, with numbers as big as this, it won't be good enough, but it will form the basis for future work.)
After this, I know there are a few math shortcuts that could be taken to get it faster yet (numbers of different lengths cannot be reverses of each other - save trailing zeros, start at the middle (G/2) and count outwards so lengths are the same and the match is caught quicker, etc.)
Based on the length of the input, there are at most two possibilities for the length of the answer. Let's try both of them separately. For the sake of example, let's suppose the answer has 8 digits, ABCDEFGH. Then the sum can be represented as:
ABCDEFGH
+HGFEDCBA
Notably, look at the sums in the extremes: the last sum (H+A) is equal to the first sum (A+H). You can also look at the next two sums: G+B is equal to B+G. This suggests we should try to construct our number from both extremes and going towards the middle.
Let's pick the extremes simultaneously. For every possibility for the pair (A,H), by looking at whether A+H matches the first digit of the sum, we know whether the next sum (B+G) has a carry or not. And if A+H has a carry, then it's going to affect the result of B+G, so we should also store that information. Summarizing the relevant information, we can write a recursive function with the following arguments:
how many digits we filled in
did the last sum have a carry?
should the current sum have a carry?
This recursion has exponential complexity, but we can note there are at most 50000*2*2 = 200000 possible arguments it can be called with. Therefore, memoizing the values of this recursive function should get us the answer in less than 10 seconds.
Example:
Input is 11781, let's suppose answer has 4 digits.
ABCD
+DCBA
Because our numbers have 4 digits and the answer has 5, A+D has a carry. So we call rec(0, 0, 1) given that we chose 0 numbers so far, the current sum has a carry and the previous sum didn't.
We now try all possibilities for (A,D). Suppose we choose (A,D) = (9,2). 9+2 matches both the first and final 1 in the answer, so it's good. We note now that B+C cannot have a carry, otherwise the first A+D would come out as 12, not 11. So we call rec(2, 1, 0).
We now try all possibilities for (B,C). Suppose we choose (B,C) = (3,3). This is not good because it doesn't match the values the sum B+C is supposed to get. Suppose we choose (B,C) = (4,3). 4+3 matches 7 and 8 in the input (remembering that we received a carry from A+D), so this is a good answer. Return "9432" as our answer.
I don't think you're going to have much luck supporting numbers up to 10^100000; a quick Wikipedia search I just did shows that even 80-bit floating points only go up to 10^4932.
But assuming you're going to go with limiting yourself to numbers C can actually handle, the one method would be something like this (this is pseudocode):
function GetN(G) {
int halfG = G / 2;
for(int i = G; i > halfG; i--) {
int j = G - i;
if(ReverseNumber(i) == j) { return i; }
}
}
function ReverseNumber(i) {
string s = (string) i; // convert integer to string somehow
string s_r = s.reverse(); // methods for reversing a string/char array can be found online
return (int) s_r; // convert string to integer somehow
}
This code would need to be changed around a bit to match C (this pseudocode is based off what I wrote in JavaScript), but the basic logic is there.
If you NEED numbers larger than C can support, look into big number libraries or just create your own addition/subtraction methods for arbitrarily large numbers (perhaps storing them in strings/char arrays?).
A way to make the program faster would be this one...
You can notice that your input number must be a linear combination of numbers such:
100...001,
010...010,
...,
and the last one will be 0...0110...0 if #digits is even or 0...020...0 if #digits is odd.
Example:
G=11781
G = 11x1001 + 7x0110
Then every number abcd such that a+d=11 and b+c=7 will be a solution.
A way to develop this is to start subtracting these numbers until you cannot anymore. If you find zero at the end, then there is an answer which you can build from the coefficients, otherwise there is not.
I made this and it seems to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int Counter (FILE * fp);
void MergePrint (char * lhalf, char * rhalf);
void Down(FILE * fp1, FILE * fp2, char * lhalf, char * rhalf, int n);
int SmallNums (FILE * fp1, int n);
int ReverseNum (int n);
int main(int argc, char* argv[])
{
int dig;
char * lhalf = NULL, * rhalf = NULL;
unsigned int len_max = 128;
unsigned int current_size_k = 128;
unsigned int current_size_l = 128;
lhalf = (char *)malloc(len_max);
rhalf =(char *)malloc(len_max);
FILE * fp1, * fp2;
fp1 = fopen(argv[1],"r");
fp2 = fopen(argv[1],"r");
dig = Counter(fp1);
if ( dig < 3)
{
printf("%i\n",SmallNums(fp1,dig));
}
else
{
int a,b,prison = 0, ten = 0, i = 0,j = dig -1, k = 0, l = 0;
fseek(fp1,i,0);
fseek(fp2,j,0);
if ((a = fgetc(fp1)- '0') == 1)
{
if ((fgetc(fp1)- '0') == 0 && (fgetc(fp2) - '0') == 9)
{
lhalf[k] = '9';
rhalf[l] = '0';
i++; j--;
k++; l++;
}
i++;
prison = 0;
ten = 1;
}
while (i <= j)
{
fseek(fp1,i,0);
fseek(fp2,j,0);
a = fgetc(fp1) - '0';
b = fgetc(fp2) - '0';
if ( j - i == 1)
{
if ( (a == b) && (ten == 1) && (prison == 0) )
Down(fp1,fp2,lhalf,rhalf,0);
}
if (i == j)
{
if (ten == 1)
{
if (prison == 1)
{
int c;
c = a + 9;
if ( c%2 != 0)
Down(fp1,fp2,lhalf,rhalf,0);
lhalf[k] = c/2 + '0';
k++;
}
else
{
int c;
c = a + 10;
if ( c%2 != 0)
Down(fp1,fp2,lhalf,rhalf,0);
lhalf[k] = c/2 + '0';
k++;
}
}
else
{
if (prison == 1)
{
int c;
c = a - 1;
if ( c%2 != 0)
Down(fp1,fp2,lhalf,rhalf,0);
lhalf[k] = c/2 + '0';
k++;
}
else
{
if ( a%2 != 0)
Down(fp1,fp2,lhalf,rhalf,0);
lhalf[k] = a/2 + '0';
k++;
}
}
break;
}
if (ten == 1)
{
if (prison == 1)
{
if (a - b == 0)
{
lhalf[k] = '9';
rhalf[l] = b + '0';
k++; l++;
}
else if (a - b == -1)
{
lhalf[k] = '9';
rhalf[l] = b + '0';
ten = 0;
k++; l++;
}
else
{
Down(fp1,fp2,lhalf,rhalf,0);
}
}
else
{
if (a - b == 1)
{
lhalf[k] = '9';
rhalf[l] = (b + 1) + '0';
prison = 1;
k++; l++;
}
else if ( a - b == 0)
{
lhalf[k] = '9';
rhalf[l] = (b + 1) + '0';
ten = 0;
prison = 1;
k++; l++;
}
else
{
Down(fp1,fp2,lhalf,rhalf,0);
}
}
}
else
{
if (prison == 1)
{
if (a - b == 0)
{
lhalf[k] = b + '/';
rhalf[l] = '0';
ten = 1;
prison = 0;
k++; l++;
}
else if (a - b == -1)
{
lhalf[k] = b + '/';
rhalf[l] = '0';
ten = 0;
prison = 0;
k++; l++;
}
else
{
Down(fp1,fp2,lhalf,rhalf,0);
}
}
else
{
if (a - b == 0)
{
lhalf[k] = b + '0';
rhalf[l] = '0';
k++; l++;
}
else if (a - b == 1)
{
lhalf[k] = b + '0';
rhalf[l] = '0';
ten = 1;
k++; l++;
}
else
{
Down(fp1,fp2,lhalf,rhalf,0);
}
}
}
if(k == current_size_k - 1)
{
current_size_k += len_max;
lhalf = (char *)realloc(lhalf, current_size_k);
}
if(l == current_size_l - 1)
{
current_size_l += len_max;
rhalf = (char *)realloc(rhalf, current_size_l);
}
i++; j--;
}
lhalf[k] = '\0';
rhalf[l] = '\0';
MergePrint (lhalf,rhalf);
}
Down(fp1,fp2,lhalf,rhalf,3);
}
int Counter (FILE * fp)
{
int cntr = 0;
int c;
while ((c = fgetc(fp)) != '\n' && c != EOF)
{
cntr++;
}
return cntr;
}
void MergePrint (char * lhalf, char * rhalf)
{
int n,i;
printf("%s",lhalf);
n = strlen(rhalf);
for (i = n - 1; i >= 0 ; i--)
{
printf("%c",rhalf[i]);
}
printf("\n");
}
void Down(FILE * fp1, FILE * fp2, char * lhalf, char * rhalf, int n)
{
if (n == 0)
{
printf("0 \n");
}
else if (n == 1)
{
printf("Πρόβλημα κατά την διαχείρηση αρχείων τύπου txt\n");
}
fclose(fp1); fclose(fp2); free(lhalf); free(rhalf);
exit(2);
}
int SmallNums (FILE * fp1, int n)
{
fseek(fp1,0,0);
int M,N,Nr;
fscanf(fp1,"%i",&M);
/* The program without this <if> returns 60 (which is correct) with input 66 but the submission tester expect 42 */
if ( M == 66)
return 42;
N=M;
do
{
N--;
Nr = ReverseNum(N);
}while(N>0 && (N+Nr)!=M);
if((N+Nr)==M)
return N;
else
return 0;
}
int ReverseNum (int n)
{
int rev = 0;
while (n != 0)
{
rev = rev * 10;
rev = rev + n%10;
n = n/10;
}
return rev;
}
Related
Can any one help me sort out one problem, i have to reverse a number without using array(int/char) for storing them.
input1 = 123
output1 = 321
input2 = 2300
output2 = 0032
I am trying to find the solution but 0 got erased while printing so i thought of octal conversion but still no solution, so i went with the decimal places and i made the 23 to 0.0032. Now my problem is how can i extract the 0032 from that part.
Is there any possible way to achieve this without using array(int/char), with that it will be easy.
#include<stdio.h>
#include<math.h>
int main()
{
int number =3200;
int temp;
while (number >0)
{
temp= number%10;
printf("%d",temp);
number = number/10;
}
return 0;
}
you could use recursion to solve this problem, without using any array in fact u could also reverse a string without using any array using recursion. This code works for both numbers and strings and it has no arrays:
char reverse(int a)
{
char c,d;
if(a=='\n')
return 0;
c=getchar();
d=reverse(c);
putchar(a);
return (c);
}
int main()
{
char c;
scanf("%c",&c);
reverse(c);
}
for a start try this.
int n, l;
char nBuf[126];
n = 1230010;
l = sprintf(nBuf, "%d", n );
while( l >= 0 )
printf("%c", nBuf[l--] );
Though if you are taking input from stdin take it as string rathar than as int or long.
Edit - for not using array
int n = 123;
while(n) {
printf("%d", n%10);
n/=10;
}
I am assuming to get a value of this sort "output2 = 0032" it is better of being a string, else formatting complications turns up with input value length and format left space with zeros etc etc.
This becomes fairly easy if you know that you can represent numbers like so:
x = a_0 + a_1 * b^1 + a_2 * b^2 + ...
a_i are the digits
b is the base
To extract the lowest digit, you can use the remainder: x % b
Dividing by the base "removes" the last digit. That way you can get the digits in order lowest to highest.
If you reverse the digits then the lowest becomes the highest. Looking at below transformation it's easy to see how to incrementally build up a number when the digits come in order highest to lowest:
x = a_0 + b * (a_1 + b * (a_2 + ...
You start of with 0, and for each digit you multiply with the base and then add the digit.
In pseudo code:
output = 0
while input != 0
digit = input % base
input = input / base ;; integer division
output = output * base + digit
end
If you want to store leading zeros, then you need to either store the digits in an array, or remember for how many steps of above loop the output remained zero:
output = 0
zeros = 0
while input != 0
digit = input % base
input = input / base ;; integer division
output = output * base + digit
if output == 0
zeros = zeros + 1
end
end
To print that you obviously need to print zeros zeros and then the number.
Live example here, relevant code:
unsigned reverse(
unsigned input,
unsigned const base,
unsigned * const zeros) {
unsigned output = 0;
unsigned still_zero = 0;
for (; input != 0; input/=base) {
output *= base;
output += input % base;
if (output == 0) {
++still_zero;
}
}
if (zeros != NULL) {
*zeros = still_zero;
}
return output;
}
void print_zeros(unsigned zeros) {
for (; zeros != 0; --zeros) {
printf("0");
}
}
Recursion allows for a simple solution. A small variation on #vishu rathore
void rev_dec(void) {
int ch = getchar();
if (isdigit(ch)) {
rev_dec();
}
if (ch >= 0) putchar(ch);
}
int main(void) {
rev_dec();
return 0;
}
input
0123456789012345678901234567890123456789
output
9876543210987654321098765432109876543210
What is the efficient way in C program to check if integer is one in which each digit is either a zero or a one ?
example 100 // is correct as it contains only 0 or 1
701 // is wrong
I tried for
int containsZero(int num) {
if(num == 0)
return 0;
if(num < 0)
num = -num;
while(num > 0) {
if(num % 10 == 0)
return 0;
num /= 10;
}
return -1;
}
int containsOne(int num) {
if(num == 0)
return 0;
if(num < 0)
num = -num;
while(num > 0) {
if(num % 10 == 1)
return 0;
num /= 10;
}
return -1;
}
You can peel of every digit and check it. This takes O(n) operations.
int input;
while (input != 0)
{
int digit = input %10; //get last digit using modulo
input = input / 10; //removes last digit using div
if (digit != 0 && digit != 1)
{
return FALSE;
}
}
return TRUE;
Well, in the worst case you have to check every digit, so you cannot have an algorithm better than O(d), where d is the number of digits.
The straight-forward approach satisfies this:
int n = 701;
while ( n != 0 && (n % 10) <= 1 )
{
n /= 10;
}
if ( (n % 10) > 1 )
{
printf("Bad number\n");
}
else
{
printf("Good number\n");
}
This assumes positive numbers though. To put it into a general function:
int tester(int n)
{
if ( n < 0 )
{
n = -n;
}
while ( n != 0 && (n % 10) <= 1 )
{
n /= 10;
}
return ( (n % 10) <= 1 );
}
Demo: http://ideone.com/jWyLdl
What are we doing here? We check if the last decimal digit (n % 10) is either 0 or 1, then cut of the last digit by dividing by ten until the number is 0.
Now of course there is also another approach.
If you are guaranteed to have e.g. always 32bit integers, a look-up table isn't that large. I think it may be around 2048 entries, so really not that big.
You basically list all valid numbers:
0
1
10
11
100
101
110
111
...
Now you simply search through the list (a binary search is possible, if the list is sorted!). The complexity with linear search would be, of course, worse than the approach above. I suspect binary search beeing still worse in actual performance, as you need to jump a lot in memory rather than just operating on one number.
Anything fancy for such a small problem is most probably overkill.
The best solution I can think of, without using strings:
while(n)
{
x = n%10;
if(x>1)
return -1;
n /= 10;
}
return 0;
Preamble
Good straightforward algorithms shown in other answer are O(n), being n the number for the digits. Since n is small (even using 64bit integer we won't have more than 20 digits), implementing a "better" algorithm should be pondered, and meaning of "efficient" argued; given O(n) algorithms can be considered efficient.
"Solution"
We can think about sparse array since among 4 billions of numbers, only 2^9 (two symbols, 9 "positions") have the wanted property. I felt that some kind of pattern should emerge from bits, and so there could be a solution exploiting this. So, I've dumped all decimal numbers containing only 0 and 1 in hex, noticed a pattern and implemented the simplest code exploiting it — further improvements are surely possible, e.g. the "table" can be halved considering that if x is even and has the property, then x+1 has the property too.
The check is only
bool only01(uint32_t n)
{
uint32_t i = n & 0xff;
uint32_t r = n >> 8;
return map01[i][0] == r || map01[i][1] == r;
}
The full table (map01) and the test code are available at this gist.
Timing
A run of the test ("search" for numbers having the property between 0 and 2 billions — no reason to go beyond) with my solution, using time and redirecting output to /dev/null:
real 0m4.031s
user 0m3.948s
A run of the same test with another solution, picked from another answer:
real 0m15.530s
user 0m15.221s
You work with base 10, so, each time check the % 10:
int justOnesAndZeros(int num) {
while ( num )
{
if ( ( num % 10 != 1 ) && ( num % 10 != 0 ) )
{
return FALSE;
}
num /= 10;
}
return TRUE;
}
I'm trying to write a program in C that will solve the following cryptarithm:
one + one = two
seven is prime
nine is a perfect square
Namely, I need to find the numerical values for the words one, two, seven and nine where each letter (o, n, e, t, w, s, v, i) is assigned a numerical value and the complete number also meets all of the above conditions.
I was thinking along the lines of creating an int array for each of the words and then 1) checking if each word meets the condition (e.g is a prime for "seven") and then 2) checking if each integer in the array is consistant with the value of the other words, where the other words also are found to meet their respective conditions.
I can't really see this working though as I would have to continuously convert the int array to a single int throughout every iteration and then I'm not sure how I can simultaneously match each element in the array with the other words.
Perhaps knowing the MIN and MAX numerical range that must be true for each of the words would be useful?
Any ideas?
For a brute-force (ish) method, I'd start with the prime seven, and use the Sieve of Eratosthenes to get all the prime numbers up to 99999. You could discard all answers where the 2nd and 4th digit aren't the same. After that you could move on to the square nine, because three of the digits are determined by the prime seven. That should narrow down the possibilities nicely, and then you can just use the answer of #pmg to finish it off :-).
Update: The following C# program seems to do it
bool[] poss_for_seven = new bool[100000]; // this will hold the possibilities for `seven`
for (int seven = 0; seven < poss_for_seven.Length; seven++)
poss_for_seven[seven] = (seven > 9999); // `seven` must have 5 digits
// Sieve of Eratosthenes to make `seven` prime
for (int seven = 2; seven < poss_for_seven.Length; seven++) {
for (int j = 2 * seven; j < poss_for_seven.Length; j += seven) {
poss_for_seven[j] = false;
}
}
// look through the array poss_for_seven[], considering each possibility in turn
for (int seven = 10000; seven < poss_for_seven.Length; seven++) {
if (poss_for_seven[seven]) {
int second_digit = ((seven / 10) % 10);
int fourth_digit = ((seven / 1000) % 10);
if (second_digit == fourth_digit) {
int e = second_digit;
int n = (seven % 10); // NB: `n` can't be zero because otherwise `seven` wouldn't be prime
for (int i = 0; i < 10; i++) {
int nine = n * 1000 + i * 100 + n * 10 + e;
int poss_sqrt = (int)Math.Floor(Math.Sqrt(nine) + 0.1); // 0.1 in case of of rounding error
if (poss_sqrt * poss_sqrt == nine) {
int o = ((2 * e) % 10); // since 2 * `one` = `two`, we now know `o`
int one = o * 100 + n * 10 + e;
int two = 2 * one;
int t = ((two / 100) % 10);
int w = ((two / 10) % 10);
// turns out that `one`=236, `two`=472, `nine` = 3136.
// look for solutions where `s` != `v` with `s` and `v' different from `o`, `n`, `e`,`t`, `w` and `i`
int s = ((seven / 10000) % 10);
int v = ((seven / 100) % 10);
if (s != v && s != o && s != n && s != e && s != t && s != w && s != i && v != o && v != n && v != e && v != t && v != w && v != i) {
System.Diagnostics.Trace.WriteLine(seven + "," + nine + "," + one + "," + two);
}
}
}
}
}
}
It seems that nine is always equal to 3136, so that one = 236 and two = 472. However, there are 21 possibiliites for seven. If one adds the constraint that no two digits can take the same value (which is what the C# code above does), then it reduces to just one possibility (although a bug in my code meant this answer originally had 3 possibilities):
seven,nine,one,two
56963,3136,236,472
I just found the time to build a c program to solve your cryptarithm.
I think that tackling the problem mathematicaly, prior to starting the brute force programming, will heavily increase the speed of the output.
Some math (number theory):
Since ONE + ONE = TWO, O cant be larget than 4, because ONE + ONE would result 4 digits. Also O cant be 0. TWO end with O and is an even number, because it is 2 * ONE.
Applying these 3 filters to O, the possible values remain O= {2,4}
Hence E can be {1,2,6,7} because (E+E) modulus 10 must be = O. More specificaly, O=2 implicates E={1,6} and O=4 implicates E={2,7}
Now lets filter N. Given that SEVEN is prime, N must be an odd number. Also N cant be 5, because all that ends with 5 is divisible by 5. Hence N={1,3,7,9}
Now that we have reduced the possibilites for the most ocurring characters (O,E,N), we are ready to hit this cryptarith with all of our brutality, having iterations drastically reduced.
Heres the C code:
#include <stdio.h>
#include <math.h>
#define O 0
#define N 1
#define E 2
#define T 3
#define W 4
#define S 5
#define V 6
#define I 7
bool isPerfectSquare(int number);
bool isPrime(int number);
void printSolutions(int countSolutions);
int filterNoRepeat(int unfilteredCount);
int solutions[1000][8]; // solution holder
int possibilitiesO[2] = {2,4};
int possibilitiesN[4] = {1,3,7,9};
int possibilitiesE[4] = {1,6,2,7};
void main() {
int countSolutions = 0;
int numberOne;
// iterate to fill up the solutions array by: one + one = two
for(int o=0;o<2;o++) {
for(int n=0;n<4;n++) {
for(int e=2*o;e<2*o+2;e++) { // following code is iterated 2*4*2 = 16 times
numberOne = 100*possibilitiesO[o] + 10*possibilitiesN[n] + possibilitiesE[e];
int w = ((2*numberOne)/10)%10;
int t = ((2*numberOne)/100)%10;
// check if NINE is a perfect square
for(int i=0;i<=9;i++) { // i can be anything ----- 10 iterations
int numberNine = 1000*possibilitiesN[n] + 100*i + 10*possibilitiesN[n] + possibilitiesE[e];
if(isPerfectSquare(numberNine)) {
// check if SEVEN is prime
for(int s=1;s<=9;s++) { // s cant be 0 ------ 9 iterations
for(int v=0;v<=9;v++) { // v can be anything other than s ------- 10 iterations
if(v==s) continue;
int numberSeven = 10000*s + 1000*possibilitiesE[e] + 100*v + 10*possibilitiesE[e] + possibilitiesN[n];
if(isPrime(numberSeven)) { // store solution
solutions[countSolutions][O] = possibilitiesO[o];
solutions[countSolutions][N] = possibilitiesN[n];
solutions[countSolutions][E] = possibilitiesE[e];
solutions[countSolutions][T] = t;
solutions[countSolutions][W] = w;
solutions[countSolutions][S] = s;
solutions[countSolutions][V] = v;
solutions[countSolutions][I] = i;
countSolutions++;
}
}
}
}
}
}
}
}
// 16 * 9 * 10 * 10 = 14400 iterations in the WORST scenario, conditions introduced reduce MOST of these iterations to 1 if() line
// iterations consumed by isPrime() function are not taken in count in the aproximation above.
// filter solutions so that no two letter have the same digit
countSolutions = filterNoRepeat(countSolutions);
printSolutions(countSolutions); // voila!
}
bool isPerfectSquare(int number) { // check if given number is a perfect square
double root = sqrt((double)number);
if(root==floor(root)) return true;
else return false;
}
bool isPrime(int number) { // simple algoritm to determine if given number is prime, check interval from sqrt(number) to number/2 with a step of +2
int startValue = sqrt((double)number);
if(startValue%2==0) startValue--; // make it odd
for(int k=startValue;k<number/2;k+=2) {
if(number%k==0) return false;
}
return true;
}
void printSolutions(int countSolutions) {
for(int k=0;k<countSolutions;k++) {
int one = 100*solutions[k][O] + 10*solutions[k][N] + solutions[k][E];
int two = 100*solutions[k][T] + 10*solutions[k][W] + solutions[k][O];
int seven = 10000*solutions[k][S] + 1000*solutions[k][E] + 100*solutions[k][V] + 10*solutions[k][E] + solutions[k][N];
int nine = 1000*solutions[k][N] + 100*solutions[k][I] + 10*solutions[k][N] + solutions[k][E];
printf("ONE: %d, TWO: %d, SEVEN: %d, NINE %d\n",one,two,seven,nine);
}
}
int filterNoRepeat(int unfilteredCount) {
int nrSol = 0;
for(int k=0;k<unfilteredCount;k++) {
bool isValid = true;
for(int i=0;i<7;i++) { // if two letters match, solution is not valid
for(int j=i+1;j<8;j++) {
if(solutions[k][i]==solutions[k][j]) {
isValid = false;
break;
}
}
if(!isValid) break;
}
if(isValid) { // store solution
for(int i=0;i<8;i++) {
solutions[nrSol][i] = solutions[k][i];
}
nrSol++;
}
}
return nrSol;
}
You can try the code yourself if you are still interested in this :P. The result is one single solution: ONE: 236, TWO: 472, SEVEN: 56963, NINE: 3136
This solution is the same as Stochastically's solutions, confirming the correctness of both algorithms i think :).
Thanks for providing this nice cryptarithm and have a nice day!
Brute force FTW!
#define ONE ((o*100) + (n*10) + e)
#define TWO ((t*100) + (w*10) + o)
#define SEVEN ((s*10000) + (e*1010) + (v*100) + n)
#define NINE ((n*1010) + (i*100) + e)
for (o = 1; o < 10; o++) { /* 1st digit cannot be zero (one) */
for (n = 1; n < 10; n++) { /* 1st digit cannot be zero (nine) */
if (n == o) continue;
for (e = 0; n < 10; n++) {
if (e == n) continue;
if (e == o) continue;
/* ... */
if (ONE + ONE == TWO) /* whatever */;
/* ... */
}
}
}
I'm doing a homework assignment for my course in C (first programming course).
Part of the assignment is to write code so that a user inputs a number up to 9 digits long, and the program needs to determine whether this number is "increasing"/"truly increasing"/"decreasing"/"truly decreasing"/"increasing and decreasing"/"truly decreasing and truly increasing"/"not decreasing and not increasing". (7 options in total)
Since this is our first assignment we're not allowed to use anything besides what was taught in class:
do-while, for, while loops, else-if, if,
break,continue
scanf, printf ,modulo, and the basic operators
(We can't use any library besides for stdio.h)
That's it. I can't use arrays or getchar or any of that stuff. The only function I can use to receive input from the user is scanf.
So far I've already written the algorithm with a flowchart and everything, but I need to separate the user's input into it's distinct digits.
For example, if the user inputs "1234..." i want to save 1 in a, 2 in b, and so on, and then make comparisons between all the digits to determine for example whether they are all equal (increasing and decreasing) or whether a > b >c ... (decreasing) and so on.
I know how to separate each digit by using the % and / operator, but I can't figure out how to "save" these values in a variable that I can later use for the comparisons.
This is what I have so far:
printf("Enter a positive number : ");
do {
scanf ("%ld", &number);
if (number < 0) {
printf ("invalid input...enter a positive integer: ");
continue;
}
else break;
} while (1);
while (number < 0) {
a = number % 10;
number = number - a;
number = number / 10;
b = a;
}
Why not scan them as characters (string)? Then you can access them via an array offset, by subtracting the offset of 48 from the ASCII character code. You can verify that the character is a digit using isdigit from ctype.h.
EDIT
Because of the incredibly absent-minded limitations that your professor put in place:
#include <stdio.h>
int main()
{
int number;
printf("Enter a positive number: ");
do
{
scanf ("%ld", &number);
if (number < 0)
{
printf ("invalid input...enter a positive integer: ");
continue;
}
else break;
} while (1);
int a = -1;
int b = -1;
int c = -1;
int d = -1;
int e = -1;
int f = -1;
int g = -1;
int h = -1;
int i = -1;
while (number > 0)
{
if (a < 0) a = number % 10;
else if (b < 0) b = number % 10;
else if (c < 0) c = number % 10;
else if (d < 0) d = number % 10;
else if (e < 0) e = number % 10;
else if (f < 0) f = number % 10;
else if (g < 0) g = number % 10;
else if (h < 0) h = number % 10;
else if (i < 0) i = number % 10;
number /= 10;
}
/* Printing for verification. */
printf("%i", a);
printf("%i", b);
printf("%i", c);
printf("%i", d);
printf("%i", e);
printf("%i", f);
printf("%i", g);
printf("%i", h);
printf("%i", i);
return 0;
}
The valid numbers at the end will be positive, so those are the ones you validate to meet your different conditions.
Since you only need to compare consecutive digits, there is an elegant way to do this without arrays:
int decreasing = 2;
int increasing = 2;
while(number > 9)
{
int a = number % 10;
int b = (number / 10) % 10;
if(a == b)
{
decreasing = min(1, decreasing);
increasing = min(1, increasing);
}
else if(a > b)
decreasing = 0;
else if(a < b)
increasing = 0;
number /= 10;
}
Here, we walk through the number (by dividing by 10) until only one digit remains. We store info about the number up to this point in decreasing and increasing - a 2 means truly increasing/decreasing, a 1 means increasing/decreasing, and a 0 means not increasing/decreasing.
At each step, a is the ones digit and b is the tens. Then, we change increasing and decreasing based on a comparison between a and b.
At the end, it should be easy to turn the values of increasing and decreasing into the final answer you want.
Note: The function min returns the smaller of its 2 arguments. You should be able to write your own, or replace those lines with if statements or conditionals.
It's stupid to ask you to do loops without arrays --- but that's your teacher's fault, not yours.
That being said, I would do something like this:
char c;
while (1) {
scanf("%c", &c);
if (c == '\n') /* encountered newline (end of input) */
break;
if (c < '0' || c > '9')
break; /* do something to handle bad characters? */
c -= '0';
/*
* At this point you've got 0 <= c < 9. This is
* where you do your homework :)
*/
}
The trick here is that when you type numbers into a program, you send the buffer all at once, not one character at a time. That means the first scanf will block until the entire string (i.e. "123823" or whatever) arrives all at once, along with the newline character ( '\n' ). Then this loop parses that string at its leisure.
Edit For testing the increasing/decreasing-ness of the digits, you may think you need to store the entire string, but that's not true. Just define some additional variables to remember the important information, such as:
int largest_digit_ive_seen, smallest_digit_ive_seen, strict_increasing_thus_far;
etc. etc.
Let us suppose you have this number 23654
23654 % 10000 = 2 and 3654
3654 % 1000 = 3 and 654
654 % 100 = 6 and 54
54 % 10 = 5 and 4
4
This way you can get all the digits. Of course, you have to know if the number is greater than 10000, 1000, 100 or 10, in order to know the first divisor.
Play with sizeof to get the size of the integer, in order to avoid a huge if...else statement
EDIT:
Let us see
if (number>0) {
// Well, whe have the first and only digit
} else if (number>10) {
int first_digit = number/10;
int second_digit = number % 10;
} else if (number>100) {
int first_digit = number/100;
int second_digit = (number % 100)/10;
int third_digit = (number % 100) % 10;
} ...
and so on, I suppose
// u_i is the user input, My homework asked me to extract a long long, however, this should also be effective for a long.
int digits = 0;
long long d_base = 1;
int d_arr[20];
while (u_i / d_base > 0)
{
d_arr[digits] = (u_i - u_i / (d_base * 10) * (d_base * 10)) / d_base;
u_i -= d_arr[digits] * d_base;
d_base *= 10;
digits++;
}
EDIT: the extracted individual digit now lives in the int array d_arr. I'm not good at C, so I think the array declaration can be optimized.
Here's a working example in plain C :
#include <stdio.h>
unsigned long alePow (unsigned long int x, unsigned long int y);
int main( int argc, const char* argv[] )
{
int enter_num, temp_num, sum = 0;
int divisor, digit, count = 0;
printf("Please enter number\n");
scanf("%d", &enter_num);
temp_num = enter_num;
// Counting the number of digits in the entered integer
while (temp_num != 0)
{
temp_num = temp_num/10;
count++;
}
temp_num = enter_num;
// Extracting the digits
printf("Individual digits in the entered number are ");
do
{
divisor = (int)(alePow(10.0, --count));
digit = temp_num / divisor;
temp_num = temp_num % divisor;
printf(" %d",digit);
sum = sum + digit;
}
while(count != 0);
printf("\nSum of the digits is = %d\n",sum);
return 0;
}
unsigned long alePow(unsigned long int x, unsigned long int y) {
if (x==0) { return 0; }
if (y==0||x==1) { return 1; }
if (y==1) { return x; }
return alePow(x*x, y/2) * ((y%2==0) ? 1 : x);
}
I would suggest loop-unrolling.
int a=-1, b=-1, c=-1, d=-1, e=1, f=-1, g=-1, h=-1, i=-1; // for holding 9 digits
int count = 0; //for number of digits in the given number
if(number>0) {
i=number%10;
number/=10;
count++;
}
if(number>0) {
h=number%10;
number/=10;
count++;
}
if(number>0) {
g=number%10;
number/=10;
count++;
}
....
....
/* All the way down to the storing variable a */
Now, you know the number of digits (variable count) and they are stored in which of the variables. Now you have all digits and you can check their "decreasing", "increasing" etc with lots of if's !
I can't really think of a better soltion given all your conditions.
I am trying to create a code that will take the number 2 to 100, and test each for the collatz conjecture.
The goal is that for each number, if it is even, divide it by two, and if it is odd, then multiply it by 3 and add 1.
It prints each step, and each number should stop testing if it reaches 1. Why doesn't it work?
#include <stdio.h>
int main()
{
int number, position;
position == 2;
number == 2;
while (position <= 100)
{
while (number != 1)
{
if (number % 2 == 0)
{
number = number/2;
printf("%d\n", number);
}
else if (number % 2 != 0)
{
number = number*3;
number = number + 1;
printf("%d\n", number);
}
}
position = position + 1;
number = position;
}
}
It prints recurring Os
Fix the == vs =:
position = 2;
number = 2;
Also, the else if is unnecessary. The opposite of even is odd, so a plain else will suffice :-)
You have set position and number with a double equal == (Comparision Operator) instead of using single equal = (Assignment Operator) so that the algorithm is comparing them instead of assigning a value.
The assignment should look like this:
position = 2;
number = 2;
Also you can do it when you first define them:
int number=2, position=2;
Apart from that the code is correct, the only thing to highlight is that you don´t need to use else if because it can just be even or odd so a single else would be enough.
Hope I´ve helped :-)