Counting problem: possible sudoko tables? - python

I'm working on a sudoko solver (python). my method is using a game tree and explore possible permutations for each set of digits by DFS Algorithm.
in order to analyzing problem, i want to know what is the count of possible valid and invalid sudoko tables?
-> a 9*9 table that have 9 one, 9 two, ... , 9 nine.
(this isn't exact duplicate by this question)
my solution is:
1- First select 9 cells for 1s: (*)
2- and like (1) for other digits (each time, 9 cells will be deleted from remaining available cells):
C(81-9,9) , C(81-9*2,9) .... =
3- finally multiply the result by 9! (permutation of 1s-2s-3s...-9s in (*))
this is not equal to accepted answer of this question but problems are equivalent. what did i do wrong?

The number of valid Sudoku solution grids for the standard 9×9 grid was calculated by Bertram Felgenhauer and Frazer Jarvis in 2005 to be 6,670,903,752,021,072,936,960.
Mathematics of Sudoku |
source
I think problem with your solution is that deleting 9 cells each time from available cells does not necessarily create a valid grid. What I mean is just deleting 9 cells won't suffice.
That is why 81! / (9!)^9 is much bigger number than actual valid solutions.
EDIT:
Permutations with repeated elements
Your solutions is almost correct if you want all the tables not just valid sudoku tables.
There is a formula:
(a+b+c+...)! / [a! b! c! ....]
Suppose there are 5 boys and 3 girls and we have 8 seats then number of different ways in which they can seat is
(5+3)! / (5! 3!)
Your problem is analogous to this one.
There are 9 1s , 9 2s ... 9 9s.
and 81 places
so answer should be (9+9+...)! / (9!)^9
Now if you multiply again by 9! then this will add duplicate arrangements to the number by shuffling them.

According to this Wikipedia article (or this OEIS sequence), there are roughly 6.6 * 10^21 different sudoku squares.

What you did wrong was the last step: you shouldn't multiply the answer by 9!. You have already counted all possible squares.
This doesn't help you much when counting the possible Sudoku-tables. One other thing you could do is to count the tables where the "row-condition" holds: that is just (9!)^9, because you just choose one permutation of 1..9 for every row.
Still closer to the Sudoku-problem is counting Latin squares. Latin square has to satisfy both the "row-condition" and "column condition". That is already a difficult problem and no closed form formula is known. Sudoku is a Latin square with the additional "subsquare-condition".

Related

Generating base set of unique 6-character combos (dup combos can exist) that total 100 combos, & all 600 chars follow a specific distribution

I began dipping my toes in Python last October, so I'm still veeeeeery new, naive, and eager to learn. My end goal is to have 100ish, 6 character combinations (characters = letters A-Z and a 0 representing blanks), with the following criteria:
1.) No duplicate characters are allowed within a single combination (Ex: 'abcdee' is NOT allowed)
2.) The order of the combinations does not matter, therefor 'fedcba' is the same combination as 'abcdef'.
3.) I'm looking to identify a base set of the minimum number of unique combinations (preferably under 10, but in the end, it shouldn't matter to me), with each combination in the base set having various copies. In total, the count of all combinations combinations should be close to 100 (100 would be pretty, but if a solution does not exist to allow this, I'll take what I can get).
**Example Format/ Example End Result ** (Base set is composed of Combos#1-6 in ex below)
Combo #1: 'ABCDE' | 23 copies
Combo #2: 'FGHIJK' | 17 copies
Combo #3: 'LMNOPQ' | 20 copies
Combo #4 'RSTUVW' | 18 copies
Combo #5 'XYZ0AE' | 12 copies
Combo #6 'IOURS' | 10 copies
4.) There are 600ish total characters that make up the 100ish combinations (again, the ish depends on the exact solution). Below is a representation of how many times each letter occurs across all 6-character combinations:
char_dist = {E: 66A: 52I: 46R: 45O: 41L: 35S: 35T: 37N: 36C: 23U: 24H: 16D: 20M: 19P: 19K: 9G: 16B: 14Y: 14V: 6W: 7F: 10X: 2J: 2Z: 2Q: 20: 2}
5.) Attached is the char_combos.csv I generated using itertools. I've tried to wrap my head around this every which way but loose, but despite my seemingly infinite number of attempts to google every possible way I can think of asking this question, I've came up short. Any suggestions folks?
Link to char_combos.csv here <

Disorderly escape-Google Foobar 2020 not passing test cases [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
The code is running fine and is executing in python compiler online but failing all test cases in the Google Foobar
from math import factorial
from collections import Counter
from fractions import gcd
def cycle_count(c, n):
cc=factorial(n)
for a, b in Counter(c).items():
cc//=(a**b)*factorial(b)
return cc
def cycle_partitions(n, i=1):
yield [n]
for i in range(i, n//2+1):
for p in cycle_partitions(n-i, i):
yield [i]+p
def solution(w, h, s):
grid=0
for cpw in cycle_partitions(w):
for cph in cycle_partitions(h):
m=cycle_count(cpw, w)*cycle_count(cph, h)
grid+=m*(s**sum([sum([gcd(i, j) for i in cpw]) for j in cph]))
return grid//(factorial(w)*factorial(h))
Check out this code which is to be executed .Would love suggestions !!!
This is a gorgeous problem, both mathematically and from the algorithmic point of view.
Let me try to explain each part.
The mathematics
This part is better read with nicely typeset formulas. See a concise explanation here where links to further reading are given.
Let me add a reference directly here: For example Harary and Palmer's Graphical enumeration, Chapter 2.
In short, there is a set (the whole set of h x w-matrices, where the entries can take any of s different values) and a group of permutations that transforms some matrices in others. In the problem the group consists of all permutations of rows and/or columns of the matrices.
The set of matrices gets divided into classes of matrices that can be transformed into one another. The goal of the problem is to count the number of these classes. In technical terminology the set of classes is called the quotient of the set by the action of the group, or orbit space.
The good thing is that there is a powerful theorem (with many generalizations and versions) that does exactly that. That is Polya's enumeration theorem. The theorem expresses the number of elements of the orbit space in terms of the value of a polynomial known in the area as Cycle Index. Now, in this problem the group is a direct product of two special groups the group of all permutations of h and w elements, respectively. The Cycle Index polynomials for these groups are known, and so are formulas for computing the Cycle Index polynomial of the product of groups in terms of the Cycle Index polynomials of the factors.
Maybe a comment worth making that motivates the name of the polynomial is the following:
Every permutation of elements can be seen as cycling disjoint subsets of those elements. For example, a permutation of (1,2,3,4,5) and can be (2,3,1,5,4), where we mean that 2 moved to the position of 1, 3 moved to the position of 2, 1 to the position of 3, 5 to the position of 4 and 4 to the position of 5. The effect of this permutation is the same as cycling 1-> 3 -> 2 and 2 back to 1, and cycling 4 -> 5 and 5 back to 4. Similar to how natural numbers can be factored into a product of prime factors, each permutation can be factored into disjoint cycles. For each permutation, the cycles are unique in a sense for each permutation. The Cycle Index polynomial is computed in terms of the number of cycles of each length for each permutation in the group.
Putting all these together we get that the total count is given by the last formula in the link.
Implementation
As seen in the final formula, we need to compute:
Partitions of a number
Greatest common divisors (gcd) of many numbers.
Factorials of many numbers.
For these, we can do:
To compute all partitions one can use the iterative algorithms here. Already written in Python here.
An efficient way to compute gcd one could use Euclidean algorithm. However, since we are going to need the gcd of all pairs of numbers in a range and each one many times. It is better to pre-compute the full table of gcd all at once by dynamic programming. If a>b, then gcd(a,b)=gcd(a-b,b). This recurrence equation allows to compute gcd of larger pairs in terms of that of smaller pairs. In the table, one has the initial values gcd(1,a)=gcd(a,1)=1 and gcd(a,a)=a, for all a.
The same happens for factorials. The formula will require the factorials of all numbers in a range many times each. So, it is better to compute them all from the bottom up using that n! = n(n-1)! and 0!=1!=1.
An implementation in Python could look like this. Feel free to improve it.
I know this is a copied code but you have to :
1) write your own factorial function
2) write your own gcd function
3) cast to string before returning final value.

Combinations of expressions with 4 elementary operations

I could not come up with a better title, for an adequate one might require the whole explanation. Also, combinations could be misleading since the problem will involve permutations.
What I want to accomplish is to outperform a brute force approach in Python at the following problem: Given the 4 elementary operations [+,-,*,/] and the digits from 1 to 9, and given all the possible combinations of 5 digits and the 4 operations without repetition (permutations) that result in a given number (treated as an integer), as in 1+5*9-3/7=45, 1-2/3+9*5=45,... obtain all the integers from the lowest possible value to the highest possible value and find out wether all the integers in the space expanse exist.
My preliminary attempt with brute force is the following:
def brute_force(target):
temp = 0
x = [i for i in range(1,10)]
numbers = [str(i) for i in x]
operators = ["+","-","*","/"]
for values in permutations(numbers,5):
for oper in permutations(operators):
formula = "".join(o + v for o,v in zip([""]+list(oper),values))
if round(eval(formula)) == int(target):
temp += 1
if temp > 0:
return True
else:
return False
for i in range(-100,100):
total = brute_force(i)
if total:
print(i)
else:
print(str(i) + 'No')
It just prints 'No' besides the integers that have not been found. As may seem obvious, all integer values can be found in the space expanse, ranging between -71 to 79.
I am sort of a newcommer both with Python and with algorithmic implementation, but I think that the algorithm has complexity O(n!), judging by the fact that permutations are involved. But if that is not the case I nevertheless want an algorithm that performs better (such as recursion or dynamic programming).
Let's compute the set of possible results only once (and in a bit simpler and faster way):
expression = [None] * 9
results = {eval(''.join(expression))
for expression[::2] in permutations('123456789', 5)
for expression[1::2] in permutations('+-*/')}
It computes all possible results in about 4.5 seconds on my laptop. Yours rewritten like this takes about 5.5 seconds. Both of which are much faster than your way of redoing all calculations for every target integer.
Using that results set, we can then answer questions instantaneously, confirming your range and showing that only -70 and 78 are missing:
>>> min(results), max(results)
(-70.71428571428571, 78.83333333333333)
>>> set(range(-70, 79)) - results
{-70, 78}
First of all, let's look at the expression analytically. You have three terms: a product P (A*B), a quotient Q (A/B), and a scalar S. You combine these with an addition and a subtraction.
Two of the terms are positive; the other is negative, so we can simply negate one of the three terms (P, Q, S) and take the sum. This cuts down the combinatorics.
Multiplication is commutative; w.l.o.g, we can assume A>B, which cuts the permutations in half.
Here are my suggestion for first efficiency:
First choose the terms of the product with A>B; 36 combinations
Then choose S from the remaining 7 digits; 7*36=252 combinations
From the last 6 digits, the possible quotients range from less-than-1 through max_digit / min_digit. Group these into equivalence classes (one set for addition, one for subtraction), rather than running through all 30 permutations. This gives us roughly 6 values per case; we now have ~1500 combinations of three terms.
For each of these combinations, we have 3 possible choices for which one to negate; total is ~4500 sums.
Is that enough improvement for a start?
Thanks to Heap Overflow for pointing out the data flow case I missed (this is professionally embarrassing :-) ).
The case A*B/C+D-E is not covered above. The approach is comparable.
First choose the terms of the product with A>B; 36 combinations
Then choose C from the remaining 7 digits; 7*36=252 combinations
There are only 38 total possible quotients; you can generate these as you wish, but with so few combinations, brute-force is also reasonable.
From the last 6 digits, you have 30 combinations, but half of them are negations of the other half. Choose D>E to start and merely make a second pass for the negative ones. Don't bother to check for duplicated differences; it's not worth the time.
You now have less than 38 quotients to combine with a quantity of differences (min 5, max 8, mean almost 7).
As it happens, a bit of examination of the larger cases (quotients with divisor of 1) and the remaining variety of digits will demonstrate that this method will cover all of the integers in the range -8 through 77, inclusive. You cannot remove 3 large numbers from the original 9 digits without leaving numbers whose difference omits needed intervals.
If you're allowed to include that analysis in your coding, you can shorten this part by reversing the search. You demonstrate the coverage for the large cases {48, 54, 56, 63, 72}, demonstrate the gap-filling for smaller quotients, and then you can search with less complication for the cases in my original posting, enjoying the knowledge that you need only 78, 79, and numbers less than -8.
I think you just need to find the permutations ONCE. Create a set out of all the possible sums. And then just do a lookup. Still sort of brute force but saves you a lot of repeated calculations.
def find_all_combinations():
x = [i for i in range(1,10)]
output_set = set()
numbers = [str(i) for i in x]
operators = ["+","-","*","/"]
print("Starting Calculations", end="")
for values in permutations(numbers,5):
for oper in permutations(operators):
formula = "".join(o + v for o,v in zip([""]+list(oper),values))
# Add all the possible outputs to a set
output_set.add(round(eval(formula)))
print(".", end="")
return output_set
output = find_all_combinations()
for i in range(-100,100):
if i in output:
print(i)
else:
print(str(i) + 'No')

How to import my data into python

I'm currently working on Project Euler 18 which involves a triangle of numbers and finding the value of the maximum path from top to bottom. It says you can do this project either by brute forcing it or by figuring out a trick to it. I think I've figured out the trick, but I can't even begin to solve this because I don't know how to start manipulating this triangle in Python.
https://projecteuler.net/problem=18
Here's a smaller example triangle:
3
7 4
2 4 6
8 5 9 3
In this case, the maximum route would be 3 -> 7 -> 4 -> 9 for a value of 23.
Some approaches I considered:
I've used NumPy quite a lot for other tasks, so I wondered if an array would work. For that 4 number base triangle, I could maybe do a 4x4 array and fill up the rest with zeros, but aside from not knowing how to import the data in that way, it also doesn't seem very efficient. I also considered a list of lists, where each sublist was a row of the triangle, but I don't know how I'd separate out the terms without going through and adding commas after each term.
Just to emphasise, I'm not looking for a method or a solution to the problem, just a way I can start to manipulate the numbers of the triangle in python.
Here is a little snippet that should help you with reading the data:
rows = []
with open('problem-18-data') as f:
for line in f:
rows.append([int(i) for i in line.rstrip('\n').split(" ")])

Generating all unique combinations for "drive ya nuts" puzzle

A while back I wrote a simple python program to brute-force the single solution for the drive ya nuts puzzle.
(source: tabbykat.com)
The puzzle consists of 7 hexagons with the numbers 1-6 on them, and all pieces must be aligned so that each number is adjacent to the same number on the next piece.
The puzzle has ~1.4G non-unique possibilities: you have 7! options to sort the pieces by order (for example, center=0, top=1, continuing in clockwise order...). After you sorted the pieces, you can rotate each piece in 6 ways (each piece is a hexagon), so you get 6**7 possible rotations for a given permutation of the 7 pieces. Totalling: 7!*(6**7)=~1.4G possibilities. The following python code generates these possible solutions:
def rotations(p):
for i in range(len(p)):
yield p[i:] + p[:i]
def permutations(l):
if len(l)<=1:
yield l
else:
for perm in permutations(l[1:]):
for i in range(len(perm)+1):
yield perm[:i] + l[0:1] + perm[i:]
def constructs(l):
for p in permutations(l):
for c in product(*(rotations(x) for x in p)):
yield c
However, note that the puzzle has only ~0.2G unique possible solutions, as you must divide the total number of possibilities by 6 since each possible solution is equivalent to 5 other solutions (simply rotate the entire puzzle by 1/6 a turn).
Is there a better way to generate only the unique possibilities for this puzzle?
To get only unique valid solutions, you can fix the orientation of the piece in the center. For example, you can assume that that the "1" on the piece in the center is always pointing "up".
If you're not already doing so, you can make your program much more efficient by checking for a valid solution after placing each piece. Once you've placed two pieces in an invalid way, you don't need to enumerate all of the other invalid combinations.
If there were no piece in the centre, this would be easy. Simply consider only the situations where piece 0 is at the top.
But we can extend that idea to the actual situation. You can consider only the situations where piece i is in the centre, and piece (i+1) % 7 is at the top.
I think the search space is quite small, though the programming might be awkward.
We have seven choices for the centre piece. Then we have 6 choices for the
piece above that but its orientation is fixed, as its bottom edge must match the top edge of the centre piece, and similarly whenever we choose a piece to go in a slot, the orientation is fixed.
There are fewer choices for the remaining pieces. Suppose for
example we had chosen the centre piece and top piece as in the picture; then the
top right piece must have (clockwise) consecutive edges (5,3) to match the pieces in
place, and only three of the pieces have such a pair of edges (and in fact we've already
chosen one of them as the centre piece).
One could first off build a table with a list
of pieces for each edge pair, and then for each of the 42 choices of centre and top
proceed clockwise, choosing only among the pieces that have the required pair of edges (to match the centre piece and the previously placed piece) and backtracking if there are no such pieces.
I reckon the most common pair of edges is (1,6) which occurs on 4 pieces, two other edge pairs ((6,5) and (5,3)) occur on 3 pieces, there are 9 edge pairs that occur on two pieces, 14
that occur on 1 piece and 4 that don't occur at all.
So a very pessimistic estimate of the number of choices we must make is
7*6*4*3*3*2 or 3024.

Categories

Resources