題目
在某次實彈射擊訓練中,班長將十個戰士圍成一圈發子彈。首先,班長給第一個戰士10顆,第二個戰士2顆,第三個戰士8顆,第四個戰士22顆,第五個戰士16顆,第六個戰士4顆,第七個戰士10顆,第八個戰士6顆,第九個戰士14顆,第十個戰士20顆。然後按如下方法將每個戰士手中的子彈進行調整:所有的戰士檢查自己手中的子彈數,如果子彈數爲奇數,則向班長再要一顆。然後每個戰士再同時將自己手中的子彈分一半給下一個戰士(第10 個戰士將手中的子彈分一半給第1個戰士)。
問需要多少次調整後,每個戰士手中的子彈數都相等?每人各有多少顆子彈?
要求輸出每輪調整後各戰士手中的子彈數。
思路
這題難度一般,就是煩,我也沒能想到更好的算法。首先就有一個很重要的問題就是檢驗每個戰士是否相等。如果不加限制的判斷的話就會導致出現O(n^2)的可能,所以我在這裏用了一個總子彈數對士兵數取模的操作,這樣可以保證只有在值爲0的時候是可以出現平均分的情況的,這樣可以大大減少循環的次數。之後就是比較平常的操作了。
代碼
public static void fenZiDan(int[]shibing){
int total = 0;//子彈總數
int times = 0;//次數
int[] temp = new int[shibing.length];//臨時記錄士兵第一次交出子彈後的數量
for(int i=0;i<shibing.length;i++){
total+=shibing[i];
}
while(true){//循環執行任務
times++;
for(int i=0;i<shibing.length;i++){
if(shibing[i]%2!=0){
total++;//向班長要一顆子彈
temp[i] = (shibing[i]+1)/2;
}else {
temp[i] =shibing[i]/2;
}
}
for(int i=0;i<shibing.length;i++){
if(i>0) {
shibing[i] = temp[i - 1] + temp[i];
}else {
shibing[i] = temp[i]+temp[temp.length-1];
}
if(i!=shibing.length-1){
System.out.print(shibing[i]+" ");
}else {
System.out.println(shibing[i]+" ");
}
}
if(total%shibing.length==0){//表示可以平均分,是子彈都相等的必要不充分條件,只有此時纔會進行檢查
boolean isEnd = true;
for(int i=1;i<shibing.length;i++){
if(shibing[0]!=shibing[i]){
isEnd = false;
break;
}
}
if(isEnd){
break;
}
}
}
System.out.println("總共進行了"+times+"次");
}