解決約瑟夫環的三種方法

假設有一圈石子,從1到n比較。而後依次每隔一個石子選出一個,直到剩餘一個;問最後選出的石子的編號是多少;spa

(至少)有三種方法能夠解決這個問題;以下面的代碼所示:scala

object App extends App {

  def native(n: Int): Int = {
    def dispatch(pre: List[Int], list: List[Int]): List[Int] =
      list match {
        case Nil => pre
        case h :: Nil => pre.tail :+ h
        case h :: x :: tail => dispatch(pre :+ h, tail)
      }

    def play(list: List[Int]): Int =
      if(list.size == 1) list.head
      else {
        play(dispatch(Nil, list))
      }

    play((1 to n).toList)
  }

  def smart(n: Int): Int = {
    val j = Array.fill(n + 1)(1)

    def calc(k: Int): Unit = {
      if(k <= n) {
        if(k % 2 == 0) {
          j(k) = 2 * j(k / 2) - 1
        } else {
          j(k) = 2 * j(k / 2) + 1
        }
        calc(k + 1)
      }
    }
    calc(2)

    j(n)
  }


  def best(n: Int): Int = {
    def binaryRep(n: Int): List[Int] = {
      if(n == 0) {
        Nil
      } else if(n == 1) {
        List(1)
      } else {
        (n % 2) :: binaryRep(n >> 1)
      }
    }

    val br = binaryRep(n).reverse

    var cycleLeftShift = br.tail :+ br.head

    def toDecimal(list: List[Int], base: Int, result: Int): Int = {
      list match {
        case Nil => result
        case h :: tail => toDecimal(tail, base * 2, result + h * base)
      }
    }
    toDecimal(cycleLeftShift.reverse, 1, 0)
  }

  for {
    i <- 1 until 15
  } {
    println(s"native: J($i) = " + native(i))
  }


  for {
    i <- 1 until 15
  } {
    println(s"smart:  J($i) = " + smart(i))
  }

  for {
    i <- 1 until 15
  } {
    println(s"best:  J($i) = " + best(i))
  }
}

這三種方法依次是是模擬,數學計算,還有利用該問題自己的特性;code

  1. 模擬的方法比較直觀,迭代屢次,直到剩餘一個元素爲止;每次迭代都依次剔除一個元素;須要注意的時,但有奇數個石子的時候,在頭部的石子也須要被剔除掉。由於是個環麼~~~ci

  2. 數學的方法是基於如下的觀察:數學

    a. 當n = 1時,J(1) = 1, it

    b. 假設n = 2k時, 假設最後編號爲J(n)的石子留了下來;通過第一輪剔除,編號爲偶數的石子都被剔除了,因此全部的石子(除去編號1)的位置都往前移動,好比編號3到位置2,編號5到位置3,等等。原有編號與新編號之間的關係爲x = 2 * y - 1; 因此有J(n) = 2 * J(k) - 1;class

    c. 當n = 2 * k + 1的時候,通過第一輪剔除,除了偶數編號的石子要被移除掉,編號爲1的石子也會被移除;因此原有編號3變爲移動到位置1,編號5移動到位置2,等等。能夠獲得關係x = 2 * y + 1; 因此有J(n) = 2 * J(k) + 1;object

  3. 第三種方法,我也不知道爲何~~~~~~List

相關文章
相關標籤/搜索