Count number of possible passwords with given constraints

时间:2016-10-20 20:05:40

标签: c mpi combinatorics

I just need some ideas to get started on this. I'm to write a program in C that counts the number of all possible passwords using the digits 0 - 9 along with some other given constraints such as:

1) Leftmost digit cannot be the same as rightmost digit

2) No two digits can appear more than twice in the pw (123242 is not valid)

3) No consecutive digits of the same value (1221 not valid)

4) 4 digits in length minimum

In addition to this, users input via command line arguments the length of the password along with an optional argument of which digit cannot be used.

What's the best approach towards doing so? My idea was to just create a large set of all possibilities without the constraints and begin searching within the set for any pw that conflicts with any of the contraints, removing them. After doing so, I count the elements within the set. I don't know how efficient that is though.

My other question is whether it is much different for me to create this as a mpi program rather than just sequential program.

2 个答案:

答案 0 :(得分:0)

Usually dynamic programming works for such tasks. Though you haven't provided the specifics, thus it's not clear whether DP will work in your case too. In the essence DP is designing a function and calculating its values with memorization. The function will look like F(n,d)=F(n-1,d1)+...+F(n-1,dK) or more complex (more variables) depending on your task. Here n is the current length of the password, d is the last digit, and d1...dK are the possible previous digits.

I've given some hints for you:

  1. Dynamic programming
  2. Memorization
  3. Looking at the last digit and the possible preceding digits

You can study more at Wikipedia or more reader-friendly tutorials (TopCoder?)

EDIT: one more tip is to use GPGPU - CUDA or OpenCL - together with or instead of MPI.

答案 1 :(得分:0)

它不是那么大的集合,不能被蛮力计算。请注意,不需要检查所有可能性,只需要通过增加&#39;数字。这意味着如果数字d不在某个位置i,则数字d-1无法位于j<i位置的密码。每长度有效增加数字密码:

  • 1:0,
  • 2:01,
  • 3:010,012,
  • 4:0101,0102,0120,0121,0123。

从一个越来越多的数字密码中,可以创建nPk个不同的密码,其中n是可能的数字位数,k是增加数字密码的已用位数。< / p>

这是这种方法的python实现。

import math
import time

_ps = {}
def _P(n, k):
    if (n, k) not in _ps:
        _ps[(n, k)] = math.factorial(n) // math.factorial(n-k)
    return _ps[(n, k)]

def _cc(length, last_digit, largest_digit, digits_left, counts, max_digit, max_length):
    counts[length] += _P(max_digit+1, largest_digit+1)
    if length < max_length:
        for d in xrange(largest_digit+1):              # Check digits 0-largest_digit
            if d != last_digit and digits_left[d] > 0:
                digits_left[d] -= 1
                _cc(length+1, d, largest_digit, digits_left, counts, max_digit, max_length)
                digits_left[d] += 1
        if largest_digit < max_digit:
            largest_digit += 1
            digits_left[largest_digit] -= 1
            _cc(length+1, largest_digit, largest_digit, digits_left, counts, max_digit, max_length)
            digits_left[largest_digit] += 1

def count_combs(max_digit, max_length, min_length=4):
    time1 = time.time()
    digits_left = [1] + [2] * max_digit  # Max 2 same digits to use
    counts = [0] * (max_length + 1)
    _cc(1, 0, 0, digits_left, counts, max_digit, max_length)
    s = 0
    for d, count in enumerate(counts[min_length:]):
        print d+min_length, count
        s += count
    print 'Sum', s
    print 'Time: %0.3f ms' % ((time.time()-time1)*1000.0,)

if __name__ == '__main__':
    import sys
    count_combs(int(sys.argv[1]), int(sys.argv[2]))

对于最大的情况,它在我的笔记本电脑上运行~11分钟。 C实现会快得多。用法是:

python <script> <max_digit> <max_password_length>
python <script> 6 20
python <script> 9 20  # The largest example

最大案件的结果是:

4 7290
5 64800
6 563040
7 4742640
8 38435040
9 297410400
10 2179668960
11 14994201600
12 95817708000
13 561778761600
14 2975712163200
15 13959599875200
16 56450035555200
17 189212904115200
18 494001259315200
19 896042510496000
20 851371260364800
Sum 2504688393448170
Time: 648185.829 ms