# 淘汰遊戲 :::success 有11 個人圍成一個圓圈,如下圖表示。從箭頭所指為開始,每隔一人,就淘汰一人,從1號開始編號,編號1開始不淘汰,(例如3號離開,5號離開…,依此類推,若超過編號11號就接回到1號繼續淘汰下去),請問最後剩下來的那個人,是編號幾號? ::: ![](https://i.imgur.com/badBuRb.png) ## 輸入說明 每次輸入兩個數字 $n$與$p$,$n$表示每次參加淘汰遊戲的人數,$p$表示間隔多少人淘汰一人,輸入$n$小於100,且$p$<$n$。 ## 輸出說明 輸出一個數字,表示最後剩下一人的編號。 ## 輸入範例 11 3 ## 輸出範例 10 ## 解題構思 1. 使用陣列進行模擬,宣告一個101個元素的陣列,陣列第一個元素不使用,也就是陣列索引值為0的元素不使用。 2. 先設定陣列中所有元素為0,若被淘汰改成1。 3. 一個變數紀錄淘汰幾個了,當剩最後一個時,就使用迴圈找出陣列值為0 的索引值,就是答案。 ### 參考程式 ```cpp= #include <iostream> #include <cstring> //for memset() #define MAX 100+5 //設定最大人數 using namespace std; int a[MAX]; // Array to store users int main() { int n; //總人數 int p; //間隔數 // 不斷讀取輸入的 n, p 直到輸入結束後停止 while(cin>>n>>p) { //將陣列的初始值全部設為0 //0:未淘汰 1:被淘汰 memset(a, 0, sizeof(a)); //模擬淘汰過程 int outs=0; //紀錄累計淘汰的人數 int steps; //從目前位置往前累計的次數 int curPos=2; //記錄下一個要被淘汰的位置 while(outs<(n-1)) { steps = 0; while(steps<p) { if(!a[curPos]) { //累計間隔人數 + 1 steps++; //如果目前位置的索引還未到最大值(n) //目前位置的索引 + 1 if(curPos<n) curPos++; //設成從第1個位置索引 else curPos=1; } else { //如果目前位置的索引還未到最大值(n) //目前位置的索引 + 1 if(curPos<n) curPos++; //設成從第1個位置索引 else curPos=1; } } //由 curPos往後找到下一個未被淘汰的位置 while(a[curPos]) { //如果目前位置的索引還未到最大值(n) //目前位置的索引 + 1 if(curPos<n) curPos++; //設成從第1個位置索引 else curPos=1; } //curPos的位置被淘汰 a[curPos] = 1; //累計淘汰人數 outs++; } //輸出結果 for(int i=1; i<=n; i++) { if(!a[i]) { cout<<i<<"\n"; break; } } } return 0; } ``` ![](https://i.imgur.com/O4OliVU.png) # 服務顧客(模擬時間的進行) ## 題目說明 1. 便利商店店員服務顧客,請幫他計算沒有顧客的時間。 2. 已知顧客到達時間與服務所需時間,假設店員服務時不用休息,當顧客到時店員若在服務其他客人,則顧客會依序排隊等待服務,若超過該店員服務時間則由下一位店員服務。 3. 時間以分鐘為單位,同時間到的客人可以任意順序進行排隊,請計算店員在指定上班時間,沒有顧客的總時間,以分鐘為單位。 ## 輸入說明 1. 每次輸入兩個數字$t$與$n$,$t$表示店員要上班幾小時,$n$表示有幾個客人需要服務。 2. 接著後面有$n$行,每行兩個數字$a$與$b$。 3. $a$表示顧客到達時間,所輸入的$a$為採用將小時與分鐘累加為累計分鐘數呈現,累計分鐘數從0開始,第一個小時為0到59,第二個小時為60到119,例如:80,表示第2小時的第20分鐘結束時,第2小時的第21分鐘剛開始時到便利商店。 4. $b$表示顧客服務所需時間,以分鐘為單位。 5. 所輸入資料會以顧客到達時間進行排序,$n$小於200人,$t$小於10小時。 ## 輸出說明 輸出一個數字,表示店員沒有顧客的總時間,以分鐘為單位。 ## 輸入範例 4 5 1 3 45 20 160 3 161 80 170 10 ## 輸出範例 137 ## 解題構思 1. 使用陣列進行模擬,宣告一個600個元素的陣列 $ser$ 先設定為0,若需要服務客人改成1。 2. 一個變數 $now$ 紀錄服務目前客人完成的時間,不斷經由客人到達時間與服務時間,更新陣列 $services$ 與變數$now$。 3. 最後統計服務時間內的陣列 $ser$ 的值等於0的個數。 ### 參考程式 ```cpp= #include <iostream> #include <cstring> // for memset() #define MAXN 200 // MAX. of the customers #define MAXT 600 // MAX. of the working time using namespace std; int arroveTime[MAXN]; //紀錄MAXN個顧客到達時間 int serviceTime[MAXN]; //紀錄MAXN個顧客所需服務時間 int services[MAXT]; //記錄所有上班時間每分鐘的狀態 int main() { int t; //儲存輸入的工作時間 int n; //儲存有幾個客人需要服務 while(cin>>t>>n){ //n個客戶到達時間與所需服務時間存入陣列 for(int i=0; i<n; i++){ cin>>arroveTime[i]>>serviceTime[i]; } //將記錄所有上班時間每分鐘的狀態的陣列全設為0 memset(services, 0, sizeof(services)); //模擬動作 int totals = t*60; //總工作時間分鐘 int now = -1; //每次開始服務時間(累加) for(int i=0; i<n; i++){ //判斷是否在上班時間 if(now>=totals) break; //不須排隊 if(now<=arroveTime[i]){ //將第i個人到達時間至服務時間的間隔設為1 for(int j=arroveTime[i]; j<arroveTime[i]+serviceTime[i]; j++){ services[j]=1; } now = arroveTime[i]+serviceTime[i]; }else{ //需要排隊 //目前可以服務時間至服務時間的間隔設為1 for(int j=now; j<=now+arroveTime[i]; j++){ services[j]=1; } now = now+serviceTime[i]; } } //輸出結果 int ans=0; for(int i=0; i<totals; i++){ if(!services[i]) ans++; } cout<<ans<<"\n"; } return 0; } ``` ![](https://i.imgur.com/MRcEvcL.png) # 神奇的蝸牛 ## 題目說明 1. 蝸牛天天往上爬,想爬到樹頂。 2. 題目只給你樹的高度,蝸牛白天往上爬,晚上休息就會往下掉,且隨著天數增加往下掉的距離會不斷增加,且往下掉增加的距離都是第一天晚上往下掉的距離的10%。 3. 例如:第一天往下掉1公尺,第二天往下掉1.1公尺,第三天往下掉1.2公尺依此類推。 4. 問第幾天爬到樹頂,或者會掉到地面,所有輸入的單位都以公尺為單位,而且都是整數。 ## 輸入說明 每次輸入三個數字$h$、$d$與$n$,$h$表示樹的高度,$d$表示蝸牛白天爬幾公尺,$n$表示蝸牛第一天晚上往下掉幾公尺。 ## 輸出說明 輸出一個數字,表示第幾天爬到樹頂,若是第一天就爬到樹頂,就輸出「第1天爬到樹頂」,或者第二天掉到地面,就輸出「第2天掉到地面」 ## 輸入範例 100 5 1 ## 輸出範例 第$84$天掉到地面 ### 參考程式 ```cpp= #include <iostream> using namespace std; int main(){ int h,d; double n; while(cin>>h>>d>>n){ int day=0; // 天數 double curHei=0; // 目前高度 double down=double(n); double n01=n*0.1; // n的10% cout<<"down="<<down; while(1){ day++; curHei+=d; if(curHei>=h||curHei<=0) break; curHei-=down; down+=n01; } if(curHei>=h) cout<<"第"<<day<<"天爬到樹頂\n"; if(curHei<=0) cout<<"第"<<day<<"天掉到地面\n"; } } ``` # 撲克牌比大小(模擬撲克牌遊戲進行) ## 題目說明 1. 兩位玩家各拿5張牌,比較兩位玩家手中的五張撲克牌的大小來決定勝負。 2. 個別牌的數字大小順序分別為$A$、$K$、$Q$、$J$、$T$、$9$、$8$、$7$、$6$、$5$、$4$、$3$、$2$。 3. 花色大小順序分別為為黑梅©、紅磚(D)、紅心(H)與黑桃(S)。 4. 所輸入資料一定可以區分兩位玩家的勝負,可以不考慮平手情形,牌由小到大如下表,編號越大牌越大,大者獲勝。 5. 這個範例很複雜,需要耐心依據題意解題。 ![](https://i.imgur.com/OXr5eNK.png) ![](https://i.imgur.com/jjDjU5d.png) ## 輸入說明 1. 輸入十張牌前面五張牌表示第一位玩家的牌,後面五張牌表示第二位玩家的牌 2. 輸入的牌由兩個字元的花色與數字組合起來,例如$S$$A$表示黑桃$A$、$D$$T$表示紅磚$10$,$C$$J$ 表示黑莓$J$,$H$$K$表示紅心$K$,依此類推。 ## 輸出說明 若第一位玩家較第二位玩家較大,就輸出「第一位玩家獲勝」,若第二位玩家較第一位玩家較大,就輸出「第二位玩家獲勝」。 ## 輸入範例 CJ CK CT C2 C4 D2 S2 H2 DJ DT ## 輸出範例 第一位玩家獲勝 ## 解題構思 1. 將撲克牌黑莓2到黑莓A轉換成數字0到12; 紅磚2到紅磚A轉換成數字0到12; 紅心2到紅心A轉換成數字0到12; 黑桃2到黑桃A轉換成數字0到12。 2. 利用將第一位與第二位玩家的撲克牌傳成數字後分別儲存到陣列fp(第一位)與陣列sp(第二位),由小到大排序fp 與sp,並統計兩位玩家五張牌中,不考慮花色只考慮數字,五張牌的數字出現個數到陣列f(第一位)與陣列s(第二位)。 3. 第一位玩家撲克牌的大小等級可以利用陣列fp 與f 進行判斷,第二位玩家撲克牌的大小等級可以利用陣列sp 與s 進行判斷。若兩位玩家的撲克牌大小等級相同,則需另外判斷最高位的牌區分出哪一方獲勝。 ### 參考程式 ```cpp= #include <iostream> #include <string> //for string 物件 #include <sstream> //for stringstream 物件 #include <cstring> //for memset() #include <algorithm> //for algorithm #define CARDS 13 //每種花色有13張牌 #define SIZE 5 //每個人的牌數 using namespace std; int user1[CARDS]; //紀錄2.3...A在5張牌中出現的次數 int user2[CARDS]; //紀錄2.3...A在5張牌中出現的次數 int src1[5]; //紀錄原來5張牌的編號 int src2[5]; //紀錄原來5張牌的編號 /* 將 poker 依據花色與點數編碼成 0~51的數字 1.梅花 1~12 2.方塊 13~25 3.紅心 26~38 4.黑桃 39~51 */ int getCardNO(string s) { int suit, num; //紀錄花色, 點數 switch(s[0]){ // 花色 case 'C': //1~12 suit=0; break; case 'D': //3~25 suit=1; break; case 'H': //26~38 suit=2; break; case 'S': //39~51 suit=3; break; } switch(s[1]){ //點數 case 'A': num=12; break; case 'K': num=11; break; case 'Q': num=10; break; case 'J': num=9; break; case 'T': num=8; break; default: num=s[1]-'2'; break; } // 回傳轉換後的編碼 return (suit*CARDS+num); } void showArray(int *poker, int size) { for(int i=0; i<size; i++){ cout<<poker[i]<<" "; } cout<<"\n"; } //判斷是否為Straight Flush同花順 bool isStraightFlush(int* src, int* points) { //Assume: 1 2 3 4 5 //最大點數 - 最小點數 = 4 if(src[4]-src[0]==4){ // 判斷5張牌的花色是否相同 //5張牌是梅花 if(src[0]>=CARDS*0 && src[4]<CARDS*1) return true; // 0~12 為 梅花 //5張牌是方塊 if(src[0]>=CARDS*1 && src[4]<CARDS*2) return true; // 13~25 為 方塊 //5張牌是紅心 if(src[0]>=CARDS*2 && src[4]<CARDS*3) return true; // 26~38 為 紅心 //5張牌是黑桃 if(src[0]>=CARDS*3 && src[4]<CARDS*4) return true; // 39~51 為 黑桃 } return false; } // 判斷 src 是否為Flush(同花) // src 已經由小到大排序 bool isFlush(int* src,int* points) { // 所有牌必須同一種花色 if(src[0]>=CARDS*0 && src[4]<CARDS*1) return true; // 0~12 為 club if(src[0]>=CARDS*1 && src[4]<CARDS*2) return true; // 13~25 為 diamond if(src[0]>=CARDS*2 && src[4]<CARDS*3) return true; // 26~38 為 heart if(src[0]>=CARDS*3 && src[4]<CARDS*4) return true; // 39~51 為 Spade return false; } //判斷5張牌是否為Straight順子 //points:5張牌點數出現的次數 bool isStraight(int* src,int* points) { // 5 6 7 8 9: 各出現1次 for(int i=0; i<CARDS; i++){ if(points[i]==1 && points[i+1]==1 && points[i+2]==1 && points[i+3]==1 && points[i+4]==1) return true; } return false; } //判斷5張牌是否為isFourOfKind(鐵支) //points:5張牌點數有一次出現4次 bool isFourOfKind(int* src,int* points) { // 0~12有一個數字出現4次 for(int i=0; i<CARDS; i++){ if(points[i]==4) return true; } return false; } // 判斷5張牌是否為 Full house(葫蘆) bool isFullHouse(int* src,int* points) { for(int i=0; i<CARDS; i++){ // 出現 1對 if(points[i]==2){ // 出現 3條: i+1開始到12有一個點數出現 3次 for(int j=i+1; j<CARDS; j++){ if(points[j]==3) return true; } } // 出現 3條 if(points[i]==3){ // 出現 1對: i+1開始到12有一個點數出現 2次 for(int j=i+1; j<CARDS; j++){ if(points[j]==2) return true; } } } return false; } // 判斷5張牌是否為Three of a Kind(三條) //points:5張牌點數有一次出現3次 bool isThreeOfKind(int* src,int* points) { // 0~12有一個數字出現3次 for(int i=0; i<CARDS; i++){ if(points[i]==3) return true; } return false; } // 判斷5張牌是否為Two Pairs(兩對) //points:5張牌點數有兩個數字出現2次 bool isTwoPairs(int* src,int* points) { // 0~12有一個數字出現2次 for(int i=0; i<CARDS; i++){ if(points[i]==2){ // 出現 1對: i+1開始到12有一個點數出現 2次 for(int j=i+1; j<CARDS; j++){ if (points[j]==2) return true; } } } return false; } // 判斷5張牌是否為One Pair(一對 ) //points:5張牌點數有一個數字出現2次 bool isOnePair(int* src,int* points) { // 0~12有一個數字出現2次 for(int i=0; i<CARDS; i++){ if(points[i]==2) return true; } return false; } //由 src 與 points 陣列來得知5張牌的等級 int getLeve1(int* src, int* points) { if(isStraightFlush(src,points)) return 9; // 同花順 else if(isFourOfKind(src,points)) return 8; // 鐵支 else if(isFullHouse(src,points)) return 7; // 葫蘆 else if(isFlush(src,points)) return 6; // 同花 else if(isStraight(src,points)) return 5; // 順子 else if(isThreeOfKind(src,points)) return 4; // 三條 else if(isTwoPairs(src,points)) return 3; // 兩對 else if(isOnePair(src,points)) return 2; // 一對 else return 1; // 散牌 } int checkLevel(int leve) { return 1; } int main() { string s; //讀取一行資料儲存的字串 while(getline(cin, s)){ //s為一行資料,資料間以空白隔開 //以s初始化stringstream物件(ss) stringstream ss(s); //將 user1, user2 紀錄2.3...A在5張牌中出現的次數的陣列全部設為0 memset(user1, 0, sizeof(user1)); memset(user2, 0, sizeof(user2)); //把輸入資料的前面5筆存入src1, user1 // 把後面5筆存入src2, user2 string tmp; int cardNo; for(int i=0; i<10; i++){ //從ss串流讀取一個字串 ss>>tmp; //將tmp編碼成0~51的數字 cardNo = getCardNO(tmp); //前面5筆存入src1, user1 if(i<5){ src1[i]=cardNo; user1[cardNo%CARDS]++; }else{ //後面5筆存入src2,user2 src2[i%SIZE]=cardNo; user2[cardNo%CARDS]++; } } //由小到大將2個人的牌點數由小到大排序 sort(src1, src1+SIZE); sort(src2, src2+SIZE); //showArray(src1, SIZE); //showArray(src2, SIZE); //取得5張牌的等級 int level1 = getLeve1(src1, user1); int level2 = getLeve1(src2, user2); if(level1>level2) cout<<"第一位玩家獲勝\n"; else if(level1<level2) cout<<"第二位玩家獲勝\n"; else{ int check = checkLevel(level1); (check==1) ? (cout<<"第一位玩家獲勝\n") : (cout<<"第二位玩家獲勝\n"); } } return 0; } ```