不用開陣列來存每個人的狀態(這是我一開始的想法)
其實可以利用一個特性:直接用變數存爆炸的「位子」
舉例 範測中 1 2 3 4 5 是2爆掉
變成1 3 4 5
然後拿炸彈的是第二個位子 3
接著4爆掉 變成1 3 5
爆炸的位子是3 所以是5拿下一個炸彈
接著1爆掉 變成3 5
爆炸的位子是1 但只會報三次 所以是3贏
現在回頭看 問題點就在要怎麼處理傳到最後一個位置後的下一個點
其實解決方法很簡單 就直接用%(取餘)
所以如果我今天要寫遞迴來處理這題:
//我使用0-index來解 所以編號應該是0 1 2 3 4 在傳炸彈時第一位需考慮 所以m要先-1
一樣舉例範測
m先減一 把第一個人減掉(小細節)
第一次遞迴 n=5 m=1 k=3
0 1 2 3 4 初始index=0
index=(index+m)%n=(0+1)/5=1 1爆 index=1
0 2 3 4
第二次遞迴 n=4 m=1 k=2(n是人數 取餘裡需要用到 k則是單純記數 沒有用)
index=(index+m)%n=(1+1)%4=2 3爆 index=2
0 2 4
第三次遞迴 n=3 m=1 k=1
index=(2+1)%3=0 0爆 index=0
2 4
最後待在index=0的2 獲得勝利
而我們用一樣的邏輯去寫後會發現:
int in(int n,int m,int k){
if(k==0) return m%n;
return (in(n+1,m,k-1)+m)%n;
}
int main(){
cin>>n>>m>>k;
m--;
cout<<in(n-k+1,m,k-1)+1;
}
跑出來的僅僅是「最後的炸彈位置」而非「最後位置上的人」
這是因為我們是正向跑計算
而因為變數是可以累加的,有交換律,所以我們用反向跑遞迴
最後的那個位置對應的就會剛好是那個人
完整程式碼(前面標頭檔啥的不寫了):
int n,m,k;
int change(int n,int m,int t){
if(t==k) return m%n;
return (change(n-1,m,t+1)+m)%n;
}
int main(){
cin>>n>>m>>k;
cout<<change(n,m,1)+1;
}
參考清大電神們的code 他們最一開始直接丟k進函式 就又少了一個變數t
只不過我個人覺得比較好算 所以還是留下來了