據說著名猶太歷史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡爲止。然而Josephus 和他的朋友並不想遵從。首先從一個人開始,越過k-2個人(因爲第一個人已經被越過),並殺掉第k個人。接着,再越過k-1個人,並殺掉第k個人。這個過程沿着圓圈一直進行,直到最終只剩下一個人留下,這個人就可以繼續活着。問題是,給定了和,一開始要站在什麼地方纔能避免被處決?Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。
----------------------------------------josephus.go------------------------------------------
package josephus import ( "container/ring" "fmt" ) type Player struct { pos int alive bool } type Josephus struct { ring *ring.Ring count int counter int startPos int orderToDie int remain int } func New(count, orderToDie int) *Josephus { r := ring.New(count) for i := 1; i < count+1; i++ { r.Value = &Player{i, true} r = r.Next() } return &Josephus{ ring: r, count: count, remain: count, counter: 0, startPos: 1, orderToDie: orderToDie, } } // Show()方法展示死亡過程,並進行標記,不從結構中移除 func (this *Josephus) Show() { for i := 1; this.remain > this.orderToDie; i++ { fmt.Printf("\n開始第%d輪,共%d人\n", i, this.remain) this.ring.Do(func(item interface{}) { player := item.(*Player) if player.alive { this.counter++ } if this.counter == this.orderToDie { player.alive = false this.counter = 0 this.remain-- fmt.Printf("player %d died \n", player.pos) } }) } } func (this *Josephus) ShowRemain() { fmt.Println() this.ring.Do(func(item interface{}) { player := item.(*Player) if player.alive { fmt.Printf("存活 %v\n", item) } }) } // Run()方法將死亡玩家和存活玩家拆分並返回 func (this *Josephus ) Run() (dead,lived *ring.Ring) { r:=this.ring for ; this.remain >= this.orderToDie; r=r.Next() { player := r.Value.(*Player) if player.alive { this.counter++ } if this.counter == this.orderToDie { player.alive = false this.counter = 0 this.remain-- r=r.Prev() deadPlayer:=r.Unlink(1) // 注意Ring的New方法創建的對象至少有一個元素,爲避免這個多餘的空元素,直接指定 if dead==nil{ dead=deadPlayer }else{ dead.Link(deadPlayer) } dead.Link(deadPlayer) } } lived=r return }
-------------------------------josephus_test.go-----------------------------------------------
package josephus import ( "testing" "fmt" ) func TestJosephus(t *testing.T) { j:=New(41,3) j.Show() j.ShowRemain() fmt.Println("----------------------------------") j2:=New(41,3) dead,lived:=j2.Run() fmt.Println("存活") lived.Do(func(item interface{}) { fmt.Printf("%d,",item.(*Player).pos) }) fmt.Println("\n死亡") dead.Do(func(item interface{}) { fmt.Printf("%d,",item.(*Player).pos) }) }