ex1:賽馬
a與b之間將進行一場賽馬比賽,c為裁判。a與b分別擁有n匹馬,這2n匹馬中每匹馬擁有的能力值都不相同。比賽前,參賽的兩人先決定自己的馬的出場順序;比賽時,a的第一匹馬將對戰b的第一匹馬,a的第二匹馬將對戰b的第二匹馬,以此類推。在每一輪的比賽當中,能力值較高的馬將獲得勝利,並記其擁有者加1分。進行過n輪比賽之後,得分較高的人將獲得最終的勝利,並贏得所有的馬。當然,可能存在平局的情況,此時算作裁判c勝利,並獲得所有的馬。
問:給定每一匹馬的能力值,裁判c能否通過重新調整馬匹參賽順序而獲得勝利?
第一行輸入乙個整數n,1<=n<=100。
第二行輸入n個整數,代表選手a所有馬匹的能力值。
第二行輸入n個整數,代表選手b所有馬匹的能力值。
如果可以平局的話,則輸出「yes」,否則輸出「no」。 4
1 2 7 8
3 4 5 6
21 2
3 4
yesno
#include//#include不確定考試是否可以使用sort()函式
#includeusing namespace std;
//若不可以使用sort(),自行定義快速排序函式,參考嚴蔚敏《資料結構c語言版》
int partition(int list, int low, int high)
list[low] = pivotkey;
return low;
}
void qsort(int list, int low, int high)
return;
}
int main()
j++;
} j = 1; //這一部分與上一部分作用相同
for (int i = n / 2 + 1; i <= n; i++)
j++;
} if (flag) ans = "yes";
} cout << ans << endl;
} return 0;
}
思路:貪心演算法
首先,因為每匹馬的能力值均不相同,所以如果n為奇數,必然兩人勝利的次數不可能相等,直接輸出「no」;
若n為偶數,輸入兩組數,並由小到大排列。
如果題目要求不可以使用自帶的sort()函式,則需要自己排序,這裡採用的是快速排序方法。
然後將兩組數分別分成前、後兩部分,
先後逐一比較a的前半部分和b的後半部分,b的前半部分和a的後半部分
只要出現前半部分的數比後半部分的數大的情況,就表示無法滿足要求
否則,可以達到要求。
ex2:猴子選大王
猴子選大王,有n只猴子,從1~n進行編號。它們按照編號的順時針方向,排成乙個圓圈,然後從第一只猴子開始報數。第一只猴子報1,以後每只猴子報的數字都是它前面猴子所報數字加1。如果乙隻猴子報的數字是m,則該猴子出列,下乙隻猴子重新從1開始報數。剩下的猴子繼續排成乙個圓圈報數,直到全部的猴子都出列為止。最後乙個出列的猴子勝出。
第一行為乙個整數t,表示測試的例子數量。接下來會有t行輸入,每一行包含兩個正整數n(0對於每個測試例子,輸出猴子大王的編號。
25 2
4 33
1如果從數學角度思考這道題,答案非常簡單。
先給出**
#includeusing namespace std;
int main(){
int t,n,m;
cin>>t;
while(t--){
while(cin>>n>>m){
int king=0;
for(int i=2;i<=n;i++)
king=(king+m)%i;
cout<
首先,我們定義乙個函式 f(n,m),n和m的含義與題中相同,函式值表示勝利者的位置(陣列下標)。
接下來,我們要證明
f(n,m)=[ f(n-1,m)+ m ] %m (*)
假設給出一組數: 1,2,3,4,5,6,7; n=7,m=3
我們觀察一下整個過程
1)從1開始報數, 3出列, 陣列變為1,2,x,4,5,6,7
2)從4開始報數,6出列,陣列變為1,2,x,4,5,x,7
3)從7開始報數,2出列,陣列變為1,x,x,4,5,x,7
4)從4開始報數,7出列,陣列變為1,x,x,4,5,x,x
5)從1開始報數,5出列,陣列變為1,x,x,4,x,x,x
6)從1開始報數,1出列,陣列變為x,x,x,4,x,x,x
4為最終的勝利者
其實,這個陣列很像乙個迴圈佇列。如果我們在每一輪,都把第1個報數的人的序號定為0,第2個報數的定為1,……,第i個報數的定為i-1,可以得到如下**:紅色為每一輪出列的數字,紫色為最終的勝利者,藍色部分是已經在前面出現過的數字,目的是為了將隊伍「補齊」序號0
1234
56第一輪123
456
7第二輪
456
7124
第三輪712
4571
第四輪457
1457
第五輪145
1451
第六輪141
4141
第七輪4
勝利者4,在最後一輪中的位置是0, 也就是 f(1,3)=0,那麼他在第六輪中的位置在哪呢?
按照公式我們有 f(2,3)=[ f(1,3)+3 ] % 2=3 %2 =1,對照表,果然如此!
那麼這是為什麼呢?
其實每當一輪報數報到m,在m出列後,相當於整個陣列向前移動了m 位(我們可以想象這是一條縱隊,每個人報出自己的數,如果他是m,就出列;否則就排到隊伍末尾去;這樣,還沒有報數的人就整體前進了m位)。
那麼反過來,已經知道勝利者在n個人的時候所站的位置,那麼他在上一輪中,站的位置就應當是這一輪的位置後移m位。
即 f(n+1,m)=f(n,m)+m,這樣我們已經理解了(*)這個公式的一半。
那麼為什麼還要再對n取模呢?
仍然看上述例子,如果不對n取模,那麼勝利者4在第六輪中的位置應當是0+3=3,然而事實上,在第六輪中僅僅只有兩個人(位置為0~1),將勝利者的位置記為3顯然是不合理的。我們已經將這個過程理解為迴圈佇列,那麼我們試著將整個隊伍「補齊」,也就是僅剩的兩人重複排隊,1,4,1,4,1,4,……, 顯然這是乙個迴圈的過程,同乙個數字所在的不同位置是對n取模同餘的。(比如1 的位置為0,2,4,……;4的位置為1,3,5,……)因此,我們將「越界」的位置模n,就得到了真實的位置。
也就是說,取模,是為了解決下標越界的問題!
現在我們再來看一下**的核心部分,是不是就很好理解了呢?
int king=0;
for(int i=2;i<=n;i++)
king=(king+m)%i;
cout<
因為最終的勝利者在最後一輪(1人)的位置(陣列下標)必然為f(1,m)=0,
則他在倒數第二輪(
2人)的位置為 f(2,m)=(f(1,m)+m)%2,
倒數第三輪(
3人)位置為f(3,m)=(f(2,m)+m)%3,
…… 那麼
n人的時候,他的位置就為f(n,m)=(f(n-1,m)+m)%
n。 這是乙個迭代的過程,而終止條件就是i=n。
注意我們求出來的是位置(0~n-1),而題目要求的是編號(1~n),所以最終輸出的結果還需要加上1。
資料結構機試複習10 求和 最短字首
給定乙個具有n個整數的陣列,問在s中是否存在3個元素a b c使得a b c 0。注意 三元組 a b c 必須是乙個非遞減順序 即a b c 輸出的結果不能重複 例如,給定陣列s 1 0 1 2 1 4 輸出 1,0,1 以及 1,1,2 1 先上乙個針對matrix的ac 輸入輸出沒有leetc...
機試常見的資料結構
北航的機試要求用標準c程式設計,所以很多c 的庫都沒法用。因此我使用最簡單的 實現了幾個常見的資料結構。標準c庫參考 1.陣列實現的棧。此處棧的元素預設為int,也可以改為其他。struct stack void push int x int pop bool isempty bool isfull...
機試之資料結構STL詳解
pair的常見用法詳解 algorithm標頭檔案下常用函式介紹 機試stl之stack 括號匹配 include include include include include using namespace std int main else if str i else while bracke...