Advertisement
Tark_Wight

naive, recursive and dynamic methods + bonus

May 1st, 2023
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 5.78 KB | Source Code | 0 0
  1. import Foundation
  2.  
  3.  
  4. //:Наивный метод, метод подстановки
  5. func combinationsNaive(n: Int, k: Int) -> Int {
  6.     var numerator = 1
  7.     var denominator = 1
  8.    
  9.     for i in 0..<k {
  10.         numerator *= n - i
  11.         denominator *= i + 1
  12.     }
  13.    
  14.     return numerator / denominator
  15. }
  16.  
  17.  
  18. //:Рекурсиыный метод
  19. func combinationsRecursive(n: Int, k: Int) -> Int {
  20.     if k == 0 || k == n {
  21.         return 1
  22.     } else {
  23.         return combinationsRecursive(n: n-1, k: k-1) + combinationsRecursive(n: n-1, k: k)
  24.     }
  25. }
  26.  
  27. //:Динамическое программирование
  28. func combinationsDynamic(n: Int, k: Int) -> Int {
  29.     var cache = [[Int]](repeating: [Int](repeating: 0, count: k+1), count: n+1)
  30.    
  31.     for i in 0...n {
  32.         for j in 0...min(i, k) {
  33.             if j == 0 || j == i {
  34.                 cache[i][j] = 1
  35.             } else {
  36.                 cache[i][j] = cache[i-1][j-1] + cache[i-1][j]
  37.             }
  38.         }
  39.     }
  40.    
  41.     return cache[n][k]
  42. }
  43.  
  44.  
  45.  
  46.  
  47.  
  48. //:Расчёт
  49. func testCombinations() {
  50.     let testCases = [(n: 5, k: 2), (n: 10, k: 3), (n: 15, k: 7), (n: 20, k: 10)]
  51.    
  52.     for (n, k) in testCases {
  53.         print("n = \(n), k = \(k)")
  54.        
  55.         // Наивный алгоритм
  56.         let startTime1 = DispatchTime.now()
  57.         let result1 = combinationsNaive(n: n, k: k)
  58.         let endTime1 = DispatchTime.now()
  59.         let time1 = Double(endTime1.uptimeNanoseconds - startTime1.uptimeNanoseconds) / 1_000_000_000
  60.         let iterations1 = k
  61.        
  62.         print("Наивный:        \(result1), время = \(time1), число итераций = \(iterations1)")
  63.        
  64.         // Рекурсивный метод
  65.         let startTime2 = DispatchTime.now()
  66.         let result2 = combinationsRecursive(n: n, k: k)
  67.         let endTime2 = DispatchTime.now()
  68.         let time2 = Double(endTime2.uptimeNanoseconds - startTime2.uptimeNanoseconds) / 1_000_000_000
  69.         let iterations2 = pow(2, Double(k))
  70.        
  71.         print("Рекурсивный:    \(result2), время = \(time2), число итераций = \(iterations2)")
  72.        
  73.         // Динамическое программирование
  74.         let startTime3 = DispatchTime.now()
  75.         let result3 = combinationsDynamic(n: n, k: k)
  76.         let endTime3 = DispatchTime.now()
  77.         let time3 = Double(endTime3.uptimeNanoseconds - startTime3.uptimeNanoseconds) / 1_000_000_000
  78.         let iterations3 = k * (k+1) / 2
  79.        
  80.         print("Динамический:      \(result3), время = \(time3), число итераций = \(iterations3)")
  81.         print()
  82.     }
  83. }
  84.  
  85.  
  86. testCombinations()
  87.  
  88.  
  89. // Как можно видеть, наивный алгоритм работает быстро для маленьких значений `n` и `k`, но становится очень медленным при увеличении этих значений.
  90. // Рекурсивный алгоритм работает лучше на больших значениях `n` и `k`, но его количество итераций растет экспоненциально.
  91. // Динамическое программирование работает быстро для всех значений `n` и `k`, и его количество итераций растет линейно.
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101. //:
  102. //: МОЙ АЛГОРИТМ + БОНУС
  103. //:
  104.  
  105.  
  106. func combinations(_ n: Int, _ k: Int) -> (result: Int, iterations: Int) {
  107.     var combinations: Double = 1
  108.     var iterations = 0
  109.    
  110.     for i in (n - k + 1)...n {
  111.         combinations *= Double(i)
  112.         iterations += 1
  113.     }
  114.    
  115.     for i in 2...k {
  116.         combinations /= Double(i)
  117.         iterations += 1
  118.     }
  119.    
  120.     return (result: Int(combinations.rounded()), iterations: iterations)
  121. }
  122.  
  123. //: Моя проверка
  124. func testCombinationsMine() {
  125.     let testCases = [
  126.         (n: 5, k: 2),
  127.         (n: 10, k: 3),
  128.         (n: 15, k: 7),
  129.         (n: 20, k: 10),
  130.         (n: 30, k: 15)
  131.     ]
  132.  
  133.     for (n, k) in testCases {
  134.         print("n = \(n), k = \(k)")
  135.  
  136.         // Naive algorithm
  137.         let startTime = DispatchTime.now()
  138.         let (result, iterations) = combinations(n, k)
  139.         let endTime = DispatchTime.now()
  140.         let time = Double(endTime.uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000_000
  141.  
  142.         print("Result: \(result)")
  143.         print("Iterations: \(iterations)")
  144.         print("Time: \(time) seconds\n")
  145.     }
  146. }
  147.  
  148. testCombinationsMine()
  149.  
  150.  
  151. //: Формула Стирлинга (бонус)
  152.  
  153.  
  154. func combinationsStirling(n: Int, k: Int) -> Double {
  155.     let logSqrt2π = 0.5 * log(2 * Double.pi)
  156.     let logNFact = log(Double(n)) + logSqrt2π + Double(n) * log(Double(n))
  157.     let logKFact = log(Double(k)) + logSqrt2π + Double(k) * log(Double(k))
  158.     let logNKDiffFact = log(Double(n - k)) + logSqrt2π + Double(n - k) * log(Double(n - k))
  159.    
  160.     let logResult = logNFact - (logKFact + logNKDiffFact)
  161.    
  162.     return exp(logResult)
  163. }
  164.  
  165. func testCombinationsStirling() {
  166.     let testCases = [
  167.         (n: 5, k: 2),
  168.         (n: 10, k: 3),
  169.         (n: 15, k: 7),
  170.         (n: 20, k: 10),
  171.         (n: 30, k: 15)
  172.     ]
  173.    
  174.     for (n, k) in testCases {
  175.         print("n = \(n), k = \(k)")
  176.        
  177.         // Stirling's approximation algorithm
  178.         let startTime = DispatchTime.now()
  179.         let result = combinationsStirling(n: n, k: k)
  180.         let endTime = DispatchTime.now()
  181.         let time = Double(endTime.uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000_000
  182.         let iterations = 1
  183.        
  184.         print("Stirling's:   \(result), time = \(time), iterations = \(iterations)")
  185.         print()
  186.     }
  187. }
  188.  
  189. testCombinationsStirling()
  190.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement