PAT 甲級 1026 Table Tennis(邏輯複雜+坑多+代碼量大容易出錯)

解題總結

1.邏輯提前理清楚,條件都用文檔寫出來
2.代碼量大的時候善用代碼塊隱藏和功能註釋
3.若限制條件交叉,則選擇以某一個爲基礎,展開不同情況往下討論

寫題路程

卡住的點:
1.不能用我自己原來的寫法(優先隊列模擬最先空餘的桌子),因爲VIP桌子編號不定,不好處理,則直接遍歷所有桌子,分類討論
2.現在隊首的顧客來時,可能已經有很多個空閒的桌子,而要取滿足要求的編號最小的桌子而非最早空閒的桌子

條件:
1.若此時有VIP桌子空閒
(1)此時已經有VIP顧客到達,則放第一個到的VIP
(2)此時沒有已經到的VIP顧客,則放第一個到的顧客
2.此時VIP顧客在隊首
(1)有空閒的VIP桌
(2)沒有空閒的VIP桌
(i)有空閒的桌
(ii)沒有空閒的桌,選最早空閒的桌子

題解思路

結合兩個限制因素分類討論,第一層大循環是顧客(此事時間),然後第二層循環內得到最早空閒的桌子,分情況討論
1.第一個空閒的桌子是VIP桌子
(1)此時有到來的vip會員
(2)此時沒有到來的vip會員
直接選此時隊首的顧客
2.第一個空閒的桌子是普通桌子
(1)隊首是vip會員
(i)此時有空閒的vip桌子,選編號最小的
(ii)此時沒有空閒的vip桌子
(a)此時有空閒的普通桌,選編號最小的
(b)此時沒有空閒的桌,選最早空閒的
(2)隊首是普通顧客
(i)選編號最小的空閒桌子(此時是取普通桌)
你一定能保證這是普通桌子嗎???

		#include <iostream>
		#include<cstdio>
		#include<algorithm>
		#include<vector>
		#include<queue>
		
		using namespace std;
		
		struct player{
		    int arrive, serve, progress, wait, isVip;
		    int used;
		};
		
		struct table{
		    int isVip, cnt, vacant;
		};
		
		vector<table> tables;
		vector<player> players;
		
		bool cmpPlayer(player a, player b){
		    return a.arrive < b.arrive;
		}
		
		bool cmpStartServe(player a, player b){
		    return a.serve < b.serve;
		}
		
		int main(){
		    int N, K, M;
		    scanf("%d", &N);
		    for(int i = 0; i < N; i++){
		        player temp;
		        int h, s, m, vip, playingTime;
		        scanf("%d:%d:%d %d%d", &h, &m, &s, &playingTime, &vip);
		        temp.arrive = 3600*h + 60*m + s;
		        temp.progress = (playingTime < 120 ? 60*playingTime: 2*60*60);
		        temp.isVip = vip;
		        temp.used = 0;
		        if(temp.arrive <  21*3600) players.push_back(temp);
		        //來晚的人不管
		    }
		    sort(players.begin(), players.end(), cmpPlayer);
		
		    //輸入顧客且排序沒問題;
		
		    scanf("%d%d", &K, &M);
		    for(int i = 0; i < K; i++){
		        table temp;
		        temp.cnt = 0, temp.vacant = 8*3600;
		        temp.isVip = 0;//忘記初始化vip
		        tables.push_back(temp);
		    }
		    //tables下標數組從0開始,而桌子編號從1開始!
		    for(int i = 0; i < M; i++){
		        int x;
		        scanf("%d", &x);
		        tables[x-1].isVip = 1;
		    }
		
		    for(int i = 0; i < players.size(); ){
		        while(players[i].used) i++;//找到沒有招待過的顧客爲止
		        if(i >= players.size()) break;//全都招待過了,退出
		        int min_vacant = 21*60*60 + 1, min_index = -1;
		        //找出編號最小的最早空閒的桌子
		
		        //但這樣無法保證有vip桌的時候讓VIP先進去啊。
		        for(int j = 0; j < tables.size(); j++){
		            if(min_vacant > tables[j].vacant){
		                min_vacant = tables[j].vacant;
		                min_index = j;
		            }
		        }
		
		        if(min_vacant >= 21*60*60) break;//已經過了時間,退
		        //若是vip桌子,若有已經到達的vip顧客就放進去
		        if(tables[min_index].isVip){
		            int j;
		            for(j = 0; j < players.size(); j++){
		                //找到隊列中一個沒服務過的vip則退出
		                if(players[j].isVip && players[j].used == 0 && players[j].arrive <= tables[min_index].vacant)
		                    break;
		            }
		            //找到了符合要求的vip,更新顧客和桌子信息
		            if(j < players.size()){
		                players[j].used = 1;
		                players[j].serve = max(players[j].arrive,min_vacant);
		                players[j].wait = (players[j].arrive<min_vacant?min_vacant-players[j].arrive:0);
		                tables[min_index].cnt++;
		                tables[min_index].vacant = players[j].serve + players[j].progress;
		            }
		            //否則直接取一個未遍歷過的第一個顧客即可
		            else{
		                players[i].used = 1;
		                players[i].serve = max(players[i].arrive,min_vacant);
		                players[i].wait = (players[i].arrive<min_vacant?min_vacant-players[i].arrive:0);
		                tables[min_index].cnt++;
		                tables[min_index].vacant = players[i].serve + players[i].progress;
		                i++;
		            }
		        }else{//找到的是普通桌子
		            //若第一個顧客是vip,則看是否有在他到來之前已經空閒的VIP桌子
		            if(players[i].isVip){
		                int qwq;
		                for(qwq = 0; qwq < tables.size(); qwq++)
		                    if(tables[qwq].isVip && tables[qwq].vacant <= players[i].arrive){
		                        min_index = qwq;
		                        break;
		                    }
		                //若找到空閒vip桌子,則將Min_index賦值爲其下標換
		
		                //沒找到空閒vip桌子,直接去空閒的編號最小的桌子.
		                if(qwq == tables.size()){
		                    //尋找一來就空閒的編號最小的桌子,有則換其下標爲Min_index
		                    int ri;
		                    for(ri = 0; ri < tables.size(); ri++)
		                        if(tables[ri].vacant <= players[i].arrive){
		                            min_index = ri;
		                            break;
		                        }
		                }
		            }
		            //第一個顧客是普通顧客
		            else{
		                //找有沒有閒置的桌,有則取編號最小的爲min_index,沒有則還是默認的min——index
		                int ri;
		                for(ri = 0; ri < tables.size(); ri++)
		                    if(tables[ri].vacant <= players[i].arrive){
		                        min_index = ri;
		                        break;
		                    }
		            }
		            players[i].used = 1;
		            players[i].serve = max(players[i].arrive,tables[min_index].vacant);
		            players[i].wait = (players[i].arrive<tables[min_index].vacant?tables[min_index].vacant-players[i].arrive:0);
		            tables[min_index].cnt++;
		            tables[min_index].vacant = players[i].serve + players[i].progress;
		            i++;
		        }
		    }
		
		    sort(players.begin(), players.end(), cmpStartServe);
		    for(int i = 0; i < players.size(); i++){
		        if(players[i].used == 0) continue;
		        int h1 = players[i].arrive/3600, m1 = (players[i].arrive - 3600*h1)/60 , s1 = players[i].arrive%60;
		        int h2 = players[i].serve/3600, m2 = (players[i].serve - 3600*h2)/60 , s2 = players[i].serve%60;
		        int wait_min = (players[i].wait + 30)/60;//等待時間四捨五入!~
		        printf("%02d:%02d:%02d %02d:%02d:%02d %d\n", h1, m1, s1, h2, m2, s2, wait_min);
		    }
		    for(int i = 0; i < tables.size(); i++){
		        if(i) printf(" ");
		        printf("%d", tables[i].cnt);
		    }
		    return 0;
		}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章