Related
I'm confused as to how exactly I would make 9 random numbers add to whatever number the user may input. Let's say the user inputs "200" as the number, how do I make it so that I could get 9 random numbers add up exactly to 200?
Obviously, the code below doesn't work the way I want it to because it's literally just 9 random numbers that don't add up to a specific number. I just have no idea how to get this built properly.
public static void RandomStats()
{
Random RandomClass = new Random();
int[] intRandomStats = {
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101)
};
// ...
}
I think your question is more of math question than a code question.
It sounds like what you are looking for is a multinomial distribution. A very naive way of generating a distribution like that would be to think of it like throwing dice. Imagine that you have 200 dice with 9 sides each. Roll all of them. Count all the ones that ended up with the 1 side up, that would be your first number. Then count the ones that ended up with the 2 side up, that would be your second number. Continue until all dice are counted. There are 200 dice, so the sum of the counts will be 200. Each count would have the same probability distribution.
The above pseudo-algorithm would not be so efficient, basically looping over each die. Maybe efficiency is not so important in your case, (and 200 is a small number, so it does not matter) so feel free to write this algorithm.
If efficiency matters, try to find an existing implementation in a library. Maybe the MathNet library would work for you? See the Sample method if you are interested. At the very least, now that you know the term "multinomial distribution" it should be a bit easier to google for inspiration.
Imagine you have a bag of 200 coins. You need to divvy those coins into 9 random piles. A pile can have all the coins in the bag, some of the coins in the bag, or no coins.
Each time you allocate coins for a pile, the number of coins in the bag gets smaller (unless you grabbed 0 coins in which case it stays the same). This new count is referenced for the next pile allocation.
var rand = new Random();
var amount = 200;
var targetOutputValueCount = 9;
var outputValues = new List<int>();
for (int i = 1; i < targetOutputValueCount; i++) // 1 less than all groups
{
var groupAmount = rand.Next(0, amount);
amount -= groupAmount;
outputValues.Add(groupAmount);
}
// for the last group, it's whatever is left over
outputValues.Add(amount);
foreach (var outputValue in outputValues)
{
Console.WriteLine(outputValue);
}
An example output would be
148
28
0
2
12
2
1
6
1
The advantage of this approach is that you are always guaranteed to have positive output numbers.
Just generate eight numbers and compute the ninth as the missing difference:
int theSum = 200;
var randomNumbers = new int[9];
for(int i = 0; i < 8; i)
{
randomNumbers[i] = random.Next(0, theSum);
}
randomNumbers[8] = theSum - randomNumbers.Sum();
The methods proposed so far are workable, but tend to produce results that are skewed. For example, forcing the last number to give the correct sum can give you a value that is a long way off the other values (and possibly negative, which might be a problem in some cases). Calculating random values in the range from zero up to the remaining sum will give you a series of numbers that rapidly approach zero.
Instead, to generate n random numbers from 0 to total, I would suggest picking n-1 random values in the range from 0 to total (inclusive). Consider each of these values as the location of a bookmark in a deck of total cards. If the deck is then separated into n piles at these bookmarks, then the number of cards in each pile will give you a uniformly distributed set of values that sum to total.
Here's some code to illustrate the idea (in C, sorry):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int cmp(const void *a, const void *b) {
return *((int*)a) - *((int*)b);
}
int main(int argc, char *argv[]) {
int nterms, total, x, i, checksum;
int *array;
srand(time(0));
if (argc != 3) return puts("Require 2 arguments: <nterms> and <total>");
nterms = atoi(argv[1]); /* N.B. Input value checks omitted. */
total = atoi(argv[2]); /* Avoid large or negative values! */
/* We want to generate nterms intervals across the range from 0 to */
/* total (inclusive), so we need an array of nterms+1 values to mark */
/* the start and end of each interval. */
array = malloc((nterms+1) * sizeof(int));
/* The first and last items in this list must be zero and total (to */
/* ensure that the list of numbers add up to the correct amount) */
array[0] = 0;
array[nterms] = total;
/* Fill the rest of the array with random values from 0 to total. */
for (i=1; i<nterms; i++) {
array[i] = rand() % (total+1);
}
/* Sort these values in ascending order. */
qsort(array, nterms+1, sizeof(int), cmp);
/* Our list of random numbers can now be calculated from the */
/* difference between each pair of values in this list. */
printf("Numbers:");
for (i=checksum=0; i<nterms; i++) {
x = array[i+1] - array[i];
checksum += x;
printf(" %d", x);
}
printf("\nTotal: %d\n", checksum);
return 0;
}
You could also repeatedly generate 9 random numbers until they sum up to the desired sum. The optimal range for the random numbers is twice the target sum (200) divided by the number of random numbers (9) because then their average will be close to 200/9.
var random = new Random();
var randomNumbers = new int[9];
int input = 200;
int optimalRange = 2 * input / randomNumbers.Length;
int iterations = 0;
do {
for (int i = 0; i < randomNumbers.Length; i++) {
randomNumbers[i] = random.Next(optimalRange);
}
iterations++;
} while (randomNumbers.Sum() != input);
Console.WriteLine($"iterations = {iterations}");
Console.WriteLine($"numbers = {String.Join(", ", randomNumbers)}");
Example output:
iterations = 113
numbers = 2, 24, 39, 28, 6, 28, 34, 17, 22
In a test I repeated one million times I got these # of iterations:
average = 98.4
min = 1
max = 1366
And in 10170 cases I got it right at the first iteration.
Thanks for the hint #DrPhil. Here's a method using linq.
Random rnd = new Random();
int[] dice = new int[200];
var sidesUp = dice.Select(x => rnd.Next(1, 10));
List<int> randomNumbers = sidesUp.GroupBy(p => p).Select(x => x.Count()).ToList();
My approach ain't too different from others, but here it is:
Started by declaring an integer with the total value;
Subtracted the user input;
Used a for loop to iterate 8 times;
Each time get the division from remaining total and remaining iterations;
Option 1:
Used previous division as the maximum random value if remaining total is less than the max value;
Option 2:
Used previous division as the maximum random value;
The 9th number is the remaining total.
//run: RandomStats(0,101,200) for your particular example.
public static void RandomStats(int min, int max, int total)
{
Random randomClass = new Random();
int[] randomStats = new int[9];
int value = 0;
int totalValue = total;
bool parsed = false;
while (!parsed)
{
Console.WriteLine("Please enter a number:");
if (int.TryParse(Console.ReadLine(), out value))
{
parsed = true;
totalValue -= value;
for (int i = 0; i < randomStats.Length-1; i++)
{
//option 1
int remainMax = (int) Math.Floor((float) totalValue / (randomStats.Length - 1 - i));
int randomValue = randomClass.Next(min, totalValue < max ? remainMax : max);
//option 2
//max = (int) Math.Floor((float) totalValue / (randomStats.Length - 1 - i));
//int randomValue = randomClass.Next(min, max);
totalValue -= randomValue;
randomStats[i] = randomValue;
}
randomStats[8] = totalValue;
}
else
{
Console.WriteLine("Not a valid input");
}
}
Console.WriteLine($"min value: {min}\tmax value: {max}\ttotal value: {total}");
int testValue = value;
Console.WriteLine("Input value - " + value);
for (int i = 0; i < randomStats.Length; i++)
{
testValue += randomStats[i];
int randomIndex = i + 1;
Console.WriteLine(randomIndex + " Random value - " + randomStats[i]);
}
Console.WriteLine("test value - " + testValue);
Console.ReadKey();
}
option 1 output:
min value: 0 max value: 101 total value: 200
Input value - 10
1 Random value - 13
2 Random value - 2
3 Random value - 95
4 Random value - 10
5 Random value - 0
6 Random value - 15
7 Random value - 10
8 Random value - 10
9 Random value - 35
test value - 200
option 2 output:
min value: 0 max value: 67* total value: 200
Input value - 10
1 Random value - 1
2 Random value - 16
3 Random value - 5
4 Random value - 29
5 Random value - 17
6 Random value - 7
7 Random value - 48
8 Random value - 19
9 Random value - 48
test value - 200
*this was still 101 but became irrelevant since I divided remaining totals by the iterations
I'm trying to do the Modified Kaprekar Numbers problem (https://www.hackerrank.com/challenges/kaprekar-numbers) which describes a Kaprekar number by
Here's an explanation from Wikipedia about the ORIGINAL Kaprekar
Number (spot the difference!): In mathematics, a Kaprekar number for a
given base is a non-negative integer, the representation of whose
square in that base can be split into two parts that add up to the
original number again. For instance, 45 is a Kaprekar number, because
45² = 2025 and 20+25 = 45.
and what I don't understand is why 10 and 100 aren't Kaprekar numbers.
10^2 = 1000 and 10 + 00 = 10
Right?
So my solution
// Returns the number represented by the digits
// in the range arr[i], arr[i + 1], ..., arr[j - 1].
// If there are no elements in range, return 0.
static int NumberInRange(int[] arr, int i, int j)
{
int result = 0;
for(; i < j; ++i)
{
result *= 10;
result += arr[i];
}
return result;
}
// Returns true or false depending on whether k
// is a Kaprekar number.
// Example: IsKaprekar(45) = true because 45^2=2025 and 20+25=45
// Example: IsKaprekar(9) = false because the set of the split
// digits of 7^2=49 are {49,0},{4,9} and
// neither of 49+0 or 4+9 equal 7.
static bool IsKaprekar(int k)
{
int square = k * k;
int[] digits = square.ToString().Select(c => (int)Char.GetNumericValue(c)).ToArray();
for(int i = 0; i < digits.Length; ++i)
{
int right = NumberInRange(digits, 0, i);
int left = NumberInRange(digits, i, digits.Length);
if((right + left) == k)
return true;
}
return false;
}
is saying all the Kaprekar numbers between 1 and 100 are
1 9 10 45 55 99 100
whereas the "right" answer is
1 9 45 55 99
In 100+00 the right is 00, which is wrong because in a kaprekar number the right may start with zero (ex: 025) but cannot be entirely 0.
Therefore you can put a condition in the loop that
if(right==0)
return false;
The reason is because 10 x 10 = 100. Then you substring the right part with a length equals d = 2, that is digit count of original value (10), then the left part would be 1.
So l = 1 and r = 00, l + r = 1, that is not equals to 10.
The same for 100. 100 x 100 = 10000. l = 10, r = 000, so l + r = 10 not equal 100.
Here is my solution in JAVA.
static void kaprekarNumbers(int p, int q) {
long[] result = IntStream.rangeClosed(p, q).mapToLong(Long::valueOf)
.filter(v -> {
int d = String.valueOf(v).length();
Long sq = v * v;
String sqSt = sq.toString();
if (sqSt.length() > 1) {
long r = Long.parseLong(sqSt.substring(sqSt.length() - d));
long l = Long.parseLong(sqSt.substring(0, sqSt.length() - d));
return r + l == v;
} else return v == 1;
}).toArray();
if (result.length > 0) {
for (long l : result) {
System.out.print(l + " ");
}
} else {
System.out.println("INVALID RANGE");
}
}
How about something like this.
static bool IsKaprekar(int k)
{
int t;
for (int digits = new String(k).length(); digits > 0; digits--, t *= 10);
long sq = k * k;
long first = sq / t;
long second = sq % t;
return k == first + second;
}
find a number to divide and mod the square with in order to split it. This number should be a factor of 10 based on the number of digits in the original number.
calculate the square.
split the square.
compare the original to the sum of the splits.
Question: Print all the number who has unique digits only.
Input : n =15
output: 1 2 3 4 5 6 7 8 9 10 12 13 14 15
Here 11 is not included because it has 1 two times, same way 123, 456 .. are also valid but 121 1344 are not valid because there is same digit more than once.
I am running loop from 1- n and checking each number.
I am using Hash-map to determine the uniqueness of number.
Is there any better solution of above problem.
i'm not sure , but something like that..
List<int> numbers = new List<int>(){};
numbers =numbers.Where(p=>validCheck(p)==true).ToList();
static bool validCheck(int n)
{
return (n.ToString().Length==n.ToString().Disctinct().Count());
}
You could use LINQ, convert the number into a string and check if the length of the string is equal to the number of distinct charchters.
for (int i = 1; i < n; i++){
if (i.ToString().Length == i.ToString().Distinct().Count())
Console.Out.Write(i + " ");
}
as a semi useful library function where you seed it with a start and how many you want.
public static IEnumerable<int> UniqueDigits(int start, int count)
{
for (var i = start; i < (start + count); i++)
{
var s = i.ToString();
if (s.Distinct().Count() == s.Length)
{
yield return i;
}
}
}
then
UniqueDigits(0,15).ToList().ForEach(Console.WriteLine);
or
foreach (var digit in UniqueDigits(100,50))
{
Console.WriteLine(digit);
}
This is how I eliminate the numbers that have a duplicate characters.
Console.Write("Input:");
int number = int.Parse(Console.ReadLine());
List<int> numbers = new List<int>();
List<int> acceptedNumbers = new List<int>();
for (int i = 1; i <= number; i++)
{
numbers.Add(i);
}
foreach (var num in numbers)
{
bool rejected = false;
char[] numChars = num.ToString().ToCharArray();
foreach (var numChar in numChars)
{
if (numChars.Where(n => n == numChar).Count() > 1)
{
rejected = true;
}
}
if (!rejected)
{
acceptedNumbers.Add(num);
}
}
acceptedNumbers.ForEach(n => Console.Write($"{n} "));
Console.Read();
A string is an IEnumerable - so you can use a LINQ statement to solve your problem:
Numbers.Where(N => N.ToString().Distinct().Count() == N.ToString().Length);
The query is checking how many characters of the string of your number distinct and comares this number with the number of total characters.
Here is the whole code printing out all distinct numbers until 20:
List<int> Numbers = new List<int>();
for (int i = 1; i <= 20; i++)
{
Numbers.Add(i);
}
IEnumerable<int> AcceptedNumbers = Numbers.Where(N => N.ToString().Distinct().Count() == N.ToString().Length);
foreach (int AcceptedNumber in AcceptedNumbers)
{
Console.WriteLine(AcceptedNumber);
}
My thoughts:
Run the Loop from 0 to n
For each batch of 10 ( like from 0 to 9 , 10 to 19, 230 to 239..), pick the digits apart from the last one. These digits map to the counter which tends to be skipped. Rest all are to be emitted. For eg : for batch 12x , pick 1 & 2 , now we know that we have to skip numbers at position 1 and 2 , and rest all are acceptable so no need to do any processing for them.
Keep the above digits in sorted manner in an arrayList and keep a pointer at index 0. Lets call it 'ptr'. While running through that batch, check if count ( which moves from 0 to 9 ) for each batch is equal to the array[ptr]. If no, emit the number out. Else, skip it and do ptr++.
When you are doing step 2, check if any digits are duplicate. If yes, skip the entire batch of 10.
There are no string operations happening, so it should bring in the efficiency
Another solution is using integer division and modulo (no number to string conversion). You can verify the uniqueness of a number with the following method (assume digits is int array having 10 elements).
public static bool IsUnique(int num) {
int[] digits = new int[10];
num = Math.Abs(num);
while (num > 0) {
int r = num % 10;
num /= 10;
digits[r] ++;
if (digits[r] > 1) {
return false;
}
}
return true;
}
Working example http://ideone.com/9emEoz
There are only 9 * 9! / (10 - n)! unique-digit numbers with n digits. For larger n, you might want a next lexicographic algorithm to avoid unnecessary iterations. (For example, there are only 544,320 7-unique-digit numbers, yet your program would need to iterate through almost 10 million numbers to produce them!)
Here's my attempt at a next lexicographic procedure for a set of n-unique-digit numbers (where n > 1):
(1) From left to right, start with the digits 10, then ascend from 2.
For example, the first 4-digit number would be 1023.
(2) Increment the right-most digit that can be incremented to the next available
higher digit unused by digits to its left. Ascend to the right of the
incremented digit with the rest of the available digits, starting with lowest.
Examples: 1023 -> 1024 (4 is unused by the digits left of 3)
^
9786 -> 9801 (8 is unused be the digits left of 7)
^
9658 -> 9670 (7 is unused by the digits left of 5)
^
I am trying to find certain coordinates of interest within a very large virtual grid. This grid does not actually exist in memory since the dimensions are huge. For the sake of this question, let's assume those dimensions to be (Width x Height) = (Int32.MaxValue x Int32.MaxValue).
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
Known data about grid:
Dimensions of the grid = (Int32.MaxValue x Int32.MaxValue).
Value at any given (x, y) coordinate = Product of X and Y = (x * y).
Given the above large set of finite numbers, I need to calculate a set of coordinates whose value (x * y) is a power of e. Let's say e is 2 in this case.
Since looping through the grid is not an option, I thought about looping through:
int n = 0;
long r = 0;
List<long> powers = new List<long>();
while (r < (Int32.MaxValue * Int32.MaxValue))
{
r = Math.Pow(e, n++);
powers.Add(r);
}
This gives us a unique set of powers. I now need to find out at what coordinates each power exists. Let's take 2^3=8. As shown in the grid above, 8 exists in 4 coordinates: (8,1), (4,2), (2,4) & (1, 8).
Clearly the problem here is finding multiple factors of the number 8 but this would become impractical for larger numbers. Is there another way to achieve this and am I missing something?
Using sets won't work since the factors don't exist in memory.
Is there a creative way to factor knowing that the number in question will always be a power of e?
The best method is to factor e into it prime components. Lets say they are as follows: {a^m, b^p, c^q}. Then you build set for each power of e, for example if m=2, p=1, q=3,
e^1 = {a, a, b, c, c, c}
e^2 = (a, a, a, a, b, b, c, c, c, c, c, c}
etc. up to e^K > Int32.MaxValue * Int32.MaxValue
then for each set you need to iterate over each unique subset of these sets to form one coordinate. The other coordinate is what remains. You will need one nested loop for each of the unique primes in e. For example:
Lets say for e^2
M=m*m;
P=p*p;
Q=q*q;
c1 = 1 ;
for (i=0 ; i<=M ; i++)
{
t1 = c1 ;
for (j=0 ; j<=P ; j++)
{
t2 = c1 ;
for (k=0 ; k<=Q ; k++)
{
// c1 holds first coordinate
c2 = e*e/c1 ;
// store c1, c2
c1 *= c ;
}
c1 = t2*b ;
}
c1 = t1*a ;
}
There should be (M+1)(P+1)(Q+1) unique coordinates.
Another solution, not as sophisticated as the idea from Commodore63, but therefore maybe a little bit simpler (no need to do a prime factorization and calculating all proper subsets):
const int MaxX = 50;
const int MaxY = 50;
const int b = 6;
var maxExponent = (int)Math.Log((long)MaxX * MaxY, b);
var result = new List<Tuple<int, int>>[maxExponent + 1];
for (var i = 0; i < result.Length; ++i)
result[i] = new List<Tuple<int, int>>();
// Add the trivial case
result[0].Add(Tuple.Create(1, 1));
// Add all (x,y) with x*y = b
for (var factor = 1; factor <= (int)Math.Sqrt(b); ++factor)
if (b % factor == 0)
result[1].Add(Tuple.Create(factor, b / factor));
// Now handle the rest, meaning x > b, y <= x, x != 1, y != 1
for (var x = b; x <= MaxX; ++x) {
if (x % b != 0)
continue;
// Get the max exponent for b in x and the remaining factor
int exp = 1;
int lastFactor = x / b;
while (lastFactor >= b && lastFactor % b == 0) {
++exp;
lastFactor = lastFactor / b;
}
if (lastFactor > 1) {
// Find 1 < y < b with x*y yielding a power of b
for (var y = 2; y < b; ++y)
if (lastFactor * y == b)
result[exp + 1].Add(Tuple.Create(x, y));
} else {
// lastFactor == 1 meaning that x is a power of b
// that means that y has to be a power of b (with y <= x)
for (var k = 1; k <= exp; ++k)
result[exp + k].Add(Tuple.Create(x, (int)Math.Pow(b, k)));
}
}
// Output the result
for (var i = 0; i < result.Length; ++i) {
Console.WriteLine("Exponent {0} - Power {1}:", i, Math.Pow(b, i));
foreach (var pair in result[i]) {
Console.WriteLine(" {0}", pair);
//if (pair.Item1 != pair.Item2)
// Console.WriteLine(" ({0}, {1})", pair.Item2, pair.Item1);
}
}
In c# how do I evenly divide 100 into 7?
So the result would be
16
14
14
14
14
14
14
The code below is incorrect as all 7 values are set to 15 (totalling 105).
double [] vals = new double[7];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = Math.Ceiling(100d / vals.Length);
}
Is there an easy way to do this in c#?
Thanks
To get my suggested result of 15, 15, 14, 14, 14, 14, 14:
// This doesn't try to cope with negative numbers :)
public static IEnumerable<int> DivideEvenly(int numerator, int denominator)
{
int rem;
int div = Math.DivRem(numerator, denominator, out rem);
for (int i=0; i < denominator; i++)
{
yield return i < rem ? div+1 : div;
}
}
Test:
foreach (int i in DivideEvenly(100, 7))
{
Console.WriteLine(i);
}
Here you go:
Func<int, int, IEnumerable<int>> f = (a, b) =>
Enumerable.Range(0,a/b).Select((n) => a / b + ((a % b) <= n ? 0 : 1))
Good luck explaining it in class though :)
Since this seems to be homework, here is a hint and not the full code.
You are doing Math.Ceiling and it converts 14.28 into 15.
The algorithm is this
Divide 100 by 7, put the result in X
Get the highest even number below X and put this in Y.
Multiply Y by 7 and put the answer in Z.
Take Z away from 100.
The answer is then 6 lots of Y plus whatever the result of step 4 was.
This algorithm may only work for this specific instance.
I'm sure you can write that in C#
Not sure if this is exactly what you are after, but I would think that if you use Math.ceiling you will always end up with too big a total. Math.floor would underestimate and leave you with a difference that can be added to one of your pieces as you see fit.
For example by this method you might end up with 7 lots of 14 giving you a remainder of 2. You can then either put this 2 into one of your pieces giving you the answer you suggested, or you could split it out evenly and add get two pieces of 15 (as suggested in one of the comments)
Not sure why you are working with doubles but wanting integer division semantics.
double input = 100;
const int Buckets = 7;
double[] vals = new double[Buckets];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = Math.Floor(input / Buckets);
}
double remainder = input % Buckets;
// give all of the remainder to the first value
vals[0] += remainder;
example for ints with more flexibility,
int input = 100;
const int Buckets = 7;
int [] vals = new int[Buckets];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = input / Buckets;
}
int remainder = input % Buckets;
// give all of the remainder to the first value
vals[0] += remainder;
// If instead you wanted to distribute the remainder evenly,
// priority to first
for (int r = 0; r < remainder;r++)
{
vals[r % Buckets] += 1;
}
It is worth pointing out that the double example may not be numerically stable in that certain input values and bucket sizes could result in leaking fractional values.