Mur de brique

 

 Le site « hackerrank.com » permet à quiconque d’y définir un profile et de tenter de résoudre des problèmes non triviaux pour prouver leur habilité en programmation. Un problème est offert et tu entres la solution dans une forme définie, tu appuies sur « verify », ils vérifient la solution avec des données et affichent une belle note à ton dossier si réussi. Un employeur peut chercher des candidats dans leur base de donnée.

 

Le problème

 Vous possédez une infinité de bloques de hauteur 1 et dont la longueur peut être de 1, 2, 3 ou 4. Avec ces bloques il faut construire un mur de hauteur n et de largeur m avec les caractéristiques suivantes :

 

 -pas de trou

 -les briques sont toutes placées horizontalement

         -le mur doit être solide avec aucune ligne droite verticale qui traverse toutes les rangées de brique (juste du mortier de haut en bas).

Combien de murs différents?

 

Voici une solution du site « medium.com »

 

#####################################################

def legoBlocks(n, m):
   MOD = (10**9 +7)

   # Step 1: O(W)
   # The number of combinations to build a single row
   # As only four kinds of sizes, so
   # base case:
   # if width is 0, combination is 1
   # if width is 1, combination is 1
   # if width is 2, combination is 2
   # if width is 3, combination is 4
   row_combinations = [1, 1, 2, 4]

   # Build row combinations up to current wall's width
   while len(row_combinations) <= m:
       row_combinations.append(sum(row_combinations[-4:]) % MOD)

   # Step 2: O(W)
   # Compute total combinations
   # for constructing a wall of height N of varying widths
   total = [pow(c, n, MOD) for c in row_combinations]

   # Step 3: O(W^2)
   # Find the number of unstable wall configurations
   # for a wall of height N of varying widths
   unstable = [0, 0]

   # Divide the wall into left part and right part,
   # and calculate the combination of left part and right part.
   # From width is 2, we start to consider about violation.
   for i in range(2, m + 1):
   # i: current total width
   # j: left width
   # i - j: right width
   # f: (left part - previous vertical violation)*right part
       f = lambda j: (total[j] - unstable[j]) * total[i - j]
   result = sum(map(f, range(1, i)))
   unstable.append(result % MOD)

   # Print the number of stable wall combinations
   return (total[m] - unstable[m]) % MOD

 

Trois étapes pour résoudre le problème

1- tous les cas une ligne

2- étendre à toutes les lignes

3- soustraire les mur instables

#####################################################

 

# solution récursive
#
MOD=10**9+7
def one_row(n): # ways to tile a single row with blocks of width 4,3,2,1
   
dp=[0]*max(n+1,5)
   dp[
0] = 1
   
for i in range(1,n+1):
       sum_=0
       
for j in range(1,4+1):
           sum_+=dp[i-j]
       dp[i] = sum_
   
return dp[n]

def all_possibilities(n, m):
   
return one_row(m) ** n

def legoBlocksR(n, m):  # n is height m is width
   # print(f"one_row {one_row(5)}")
   
if m == 1: return 1
   
all_poss = all_possibilities(n, m) % MOD
   
# print(f"all_poss {all_poss}")
   
broken = 0
   
for i in range(1, m):
       broken += (legoBlocksR(n, i) * all_possibilities(n, m - i))
   
return (all_poss - broken) % MOD
#
# fin solution récursive

###############################################

 

Autre solution non récursive prise sur YouTube d’une dame qui participe au concours « hackerrank »

url : www.youtube.com/watch?v=u9fL52Hryiw

#solution dame video
def legoBlocksD(h,w):
   modulo =
10**9+7
   
row = [0 for _ in range(w+1)]
   
if w>=1:
       row[
1] = 1
   
if w>=2:
       row[
2] = 2
   
if w>=3:
       row[
3] = 4
   
if w>=4:
       row[
4] = 8
   
if w>=5:
       
for i in range(5,w+1):
           row[i] = (row[i-1]+row[i-2]+row[i-3]+row[i-4]) % modulo

   total = row.copy()
   
for _ in range(2,h+1):
       
for i in range(w+1):
           total[i] = (row[i] * total[i]) % modulo

   solid = [
0 for _ in range(w+1)]
   solid[
1] = 1
   
for ww in range(2, w+1):
       unsolid_sum =
0
       
for i in range(1,w):
           unsolid_sum += ((solid[i]*total[ww-i]) % modulo)
       solid[ww] = (total[ww] - unsolid_sum) % modulo

   
return solid[w] % modulo

##########################################