題目:
n(n<20)個人站成一圈,逆時針編號為1~n。 有兩個**,a從1開始逆時針數,b從n開始順時針數。 在每一輪中,**a數k個就停下來,**b數m個就停下來(注意有可能兩個**停在同乙個人上)。 接下來被**選中的人(1個或者2個)離開隊伍。輸入n,k,m輸出每輪裡被選中的人的編號(如果有兩個人,先輸出被a選中的)。 例如,n=10,k=4,m=3,輸出為4 8, 9 5, 3 1, 2 6, 10, 7。 注意:輸出的每個數應當恰好佔3列。
解析:
注意題目的描述及示例,可以看出:要想經過1號,就要從n號開始逆時針走;要想經過n號,就要從1號開始順時針走;因此有:p1=n;p2=1;
圖示如下:
對於環狀問題,首先想到的就是求餘的方法,假設起始點為p,那麼每移動乙個點的原始的寫法是:
p=(p+1)%n; //逆時針
p=(p-1)%n; //順時針
這樣寫有沒有問題呢?我們需要考慮邊界條件。分為兩種情況:
1.當逆時針移動時,考慮到n對n求餘等於0的時候(因為圈內沒有為0的點),此時p=(n-1);對應上面的示範為n=9。我們希望下乙個元素求餘等於10----這顯然是不可能的,因為乙個數對n求餘,其結果x一定滿足:0<=x<=(n-1)
如何解決這個問題呢?不妨讓求餘結果為(n-1),最終結果再加上1,就可以達到n了。
其實也就是用當前的值減一再對n進行求餘,最終結果+1。表示式:
p=(p+d-1)%n+1; //其中d代表正一或負一(順時針或者逆時針走)
2.當順時針移動時,仍然考慮邊界條件。當p=1時,移動後的下乙個值應該到了10 。可是帶入資料卻發現餘數為0 。回顧逆時針的情況,最終的結果可以由餘9加1得到,餘9顯然在p=n-1時成立,因此表示式為:
p=(p+d+n-1)%n+1;
觀察上面兩個表示式,發現他們的差別僅僅是d的符號不同–這可以用傳不同引數來改變,以及差了乙個週期n–對於求餘來說,加減n的倍數最終的結果是不改變的。
**:
#include#include#include#include#include#include#include#define maxn 10000
using namespace std;
int n, k, m, a[maxn];
int go(int p,int d,int t)
while (a[p] == 0); //跳到非零的地方
} return p;
}int main()
a[p1] = a[p2] = 0;
if (left) printf(",");
} printf("\n");
} system("pause");
return 0;
}
救濟金發放
題目 n n 20 個人站成一圈,逆時針編號為1 n。有兩個 a從1開始逆時針數,b從n開始順時針數。在每一輪中,a數k個就停下來,b數m個就停下來 注意有可能兩個 停在同乙個人上 接下來被 選中的人 1個或者2個 離開隊伍。輸入n,k,m輸出每輪裡被選中的人的編號 如果有兩個人,先輸出被a選中的 ...
救濟金發放
n n 20 個人站成一圈,逆時針編號為1 n。有兩個 a從1開始逆時針數,b從n開始順時針數。在每一輪中,a數k個就停下來,b數m個就停下來 注意有可能兩個 停在同乙個人上 接下來被 選中的人 1個或者2個 離開隊伍。輸入n,k,m輸出每輪裡被選中的人的編號 如果有兩個人,先輸出被a選中的 例如,...
救濟金發放
前言 這個問題琢磨了挺長時間,發現裡面有很多需要考慮和注意的 問題描述 n n 20 個人站成一圈,逆時針編號為1 n。有兩個 a從1開始逆時針數,b從n開始順時針數。在每一輪中,a數k個就停下來,b數m個就停下來 注意有可能兩個 停在同乙個人上 接下來被 選中的人 1個或者2個 離開隊伍。輸入n,...