L2-2 口罩發放 (25分)
1.題意
某市出於給市民發放口罩的需要,推出了一款小程序讓市民填寫信息,方便工作的開展。小程序收集了各種信息,包括市民的姓名、身份證、身體情況、提交時間等,但因為數據量太大,需要根據一定規則進行篩選和處理,請你編寫程序,按照給定規則輸出口罩的寄送名單。輸入格式:輸入第一行是兩個正整數 D 和 P,表示有 D 天的數據,市民兩次獲得口罩的時間至少需要間隔 P 天。接下來 D 塊數據,每塊給出一天的申請信息。第 i 塊數據的第一行是兩個整數Ti,Si,表示在第 i 天有Ti條申請,總共有Si個口罩發放名額。隨后Ti行,每行給出一條申請信息,格式如下:
姓名 身份證號 身體情況 提交時間
給定數據約束如下:
姓名 是一個長度不超過 10 的不包含空格的非空字符串;
身份證號 是一個長度不超過 20 的非空字符串;
身體情況 是 0 或者 1,0 表示自覺良好,1 表示有相關症狀;
提交時間 是 hh:mm,為24小時時間(由 00:00 到 23:59。例如 09:08。)。注意,給定的記錄的提交時間不一定有序;
身份證號 各不相同,同一個身份證號被認為是同一個人,數據保證同一個身份證號姓名是相同的。
能發放口罩的記錄要求如下:
身份證號 必須是 18 位的數字(可以包含前導0);
同一個身份證號若在第 i 天申請成功,則接下來的 P 天不能再次申請。也就是說,若第 i 天申請成功,則等到第 i+P+1 天才能再次申請;
在上面兩條都符合的情況下,按照提交時間的先后順序發放,直至全部記錄處理完畢或 Si個名額用完。如果提交時間相同,則按照在列表中出現的先后順序決定。
輸出格式:
對於每一天的申請記錄,每行輸出一位得到口罩的人的姓名及身份證號,用一個空格隔開。順序按照發放順序確定。在輸出完發放記錄后,你還需要輸出有合法記錄的、身體狀況為 1 的申請人的姓名及身份證號,用空格隔開。順序按照申請記錄中出現的順序確定,同一個人只需要輸出一次。
2.題解
用結構體存市民的信息,一個全局vector存有症狀的市民,一個局部vector存每一天的市民信息,根據題意篩選排序后發放口罩,並記錄有症狀的市民。
3.代碼

1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long; 4 const int maxn = 1000 + 5; 5 const int INF = 0x7FFFFFFF; 6 struct mmp { 7 string name; 8 string idcard; 9 int shen; 10 int times; 11 int index; 12 }; 13 map<string, int> mp; 14 set<string> smp; 15 set<string> vHave; 16 vector<mmp> v; 17 bool cmp(mmp a, mmp b) { 18 if(a.times == b.times) { 19 return a.index < b.index; 20 } 21 return a.times < b.times; 22 } 23 int main() { 24 int D, P; 25 scanf("%d %d", &D, &P); 26 for(int day = 1; day <= D; day++) { 27 int ti, si; 28 cin >> ti >> si; 29 vector<mmp> use; 30 for(int i = 1; i <= ti; i++) { 31 string name; 32 string idcard; 33 int shen; 34 int hh; 35 int mm; 36 cin >> name; 37 cin >> idcard; 38 cin >> shen; 39 scanf("%d:%d", &hh, &mm); 40 bool flag = true; 41 if(idcard.length() != 18) { 42 continue; 43 } 44 for(int j = 0; j < idcard.size(); j++) { 45 if (!(idcard[j] >= '0' && idcard[j] <= '9')) { 46 flag = false; 47 } 48 } 49 if(flag) { 50 if(shen && vHave.find(idcard) == vHave.end()) { 51 v.push_back(mmp{name, idcard, shen, hh * 60 + mm, i}); 52 vHave.insert(idcard); 53 } 54 use.push_back(mmp{name, idcard, shen, hh * 60 + mm, i}); 55 } 56 } 57 sort(use.begin(), use.end(), cmp); 58 int now = 0; 59 for(int i = 0; i < use.size() && now < si; i++) { 60 if(mp[use[i].idcard] == 0 || day >= P + mp[use[i].idcard] + 1) { 61 now++; 62 mp[use[i].idcard] = day; 63 cout << use[i].name << " " << use[i].idcard << endl; 64 } 65 } 66 } 67 for(int i = 0; i < v.size(); i++) { 68 cout << v[i].name << " " << v[i].idcard << endl; 69 } 70 71 return 0; 72 }
L2-3 完全二叉樹的層序遍歷 (25分)
1.題意
給出一棵完全二叉樹的后序遍歷,輸出對應層序遍歷。
2.題解
因為是后序遍歷序列,所以最后一個元素是樹的根節點,可以使用遞歸建樹。若當前結點的右子樹不為空則繼續將右子樹遍歷,若右子樹為空則判斷當前結點是否存在右兒子,右兒子的編號為 this.num*2+1,如果右兒子的編號小於等於結點的數量n則表示存在右兒子,在此新建結點;若右子樹不滿足條件則考慮左子樹,同樣是假如當前結點的左子樹不為空則繼續向左子樹遍歷,否則判斷當前結點是否存在左兒子,左兒子的編號為 this.num*2,如果左兒子的編號小於等於結點的數量n則表示存在左兒子,在此新建結點。最后使用隊列實現層序遍歷。
3.代碼

1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 int a[35]; 5 struct node { 6 int value; 7 int level; 8 node* l; 9 node* r; 10 node(int value) { 11 this->value = value; 12 this->l = NULL; 13 this->r = NULL; 14 this->level = 1; 15 } 16 }; 17 bool flag; 18 void build(node* root, int a, int num) { 19 if(flag) { 20 return ; 21 } 22 if(root->r) { 23 build(root->r, a, num * 2 + 1); 24 } else if(num * 2 + 1 <= n) { 25 flag = true; 26 root->r = new node(a); 27 return; 28 } 29 if(flag) { 30 return ; 31 } 32 if(root->l) { 33 build(root->l, a, num * 2); 34 } else if(num * 2 <= n) { 35 flag = true; 36 root->l = new node(a); 37 return; 38 } 39 } 40 int res[50]; 41 int cnt=0; 42 void levelOrder(node* root) { 43 queue<node*> q; 44 node* now = root; 45 q.push(now); 46 while(q.size()) { 47 now = q.front(); 48 res[cnt++] = now->value; 49 q.pop(); 50 if(now->l) { 51 q.push(now->l); 52 } 53 if(now->r) { 54 q.push(now->r); 55 } 56 } 57 } 58 int main() { 59 cin >> n; 60 for(int i = 1; i <= n; i++) { 61 cin >> a[i]; 62 } 63 reverse(a + 1, a + n + 1); 64 node* root = new node(a[1]); 65 for(int i = 2; i <= n; i++) { 66 flag = false; 67 build(root, a[i], 1); 68 } 69 levelOrder(root); 70 for(int i = 0; i < cnt; i++) { 71 cout << res[i] << (i == n - 1?'\n':' '); 72 } 73 74 return 0; 75 }
L2-4 網紅點打卡攻略 (25分)
1.題意
大家來網紅點游玩,俗稱“打卡”。在各個網紅點打卡的方法稱為“攻略”。你的任務就是從一大堆攻略中,找出那個能在每個網紅點打卡僅一次、並且路上花費最少的攻略。
輸入格式:
首先第一行給出兩個正整數:網紅點的個數 N和網紅點之間通路的條數 M。隨后 M 行,每行給出有通路的兩個網紅點、以及這條路上的旅行花費(為正整數),格式為“網紅點1 網紅點2 費用”,其中網紅點從 1 到 N 編號;同時也給出你家到某些網紅點的花費,格式相同,其中你家的編號固定為 0。再下一行給出一個正整數 K,是待檢驗的攻略的數量。隨后 K 行,每行給出一條待檢攻略,格式為:n V1 V2 ⋯ Vn,其中 n是攻略中的網紅點數,Vi是路徑上的網紅點編號。這里假設你從家里出發,從V1開始打卡,最后從Vn回家。
輸出格式:
在第一行輸出滿足要求的攻略的個數。
在第二行中,首先輸出那個能在每個網紅點打卡僅一次、並且路上花費最少的攻略的序號(從 1 開始),然后輸出這個攻略的總路費,其間以一個空格分隔。如果這樣的攻略不唯一,則輸出序號最小的那個。
2.題解
用一個二維數組存無向圖的信息,bool數組判斷是否去了每一個地點一次,更新最低花費。
3.代碼

1 #include<bits/stdc++.h> 2 #define N 205 3 using namespace std; 4 int n, m, k, nk; 5 int g[N][N]; 6 int V[N]; 7 bool vis[N]; 8 int cnt, ans_i, ans_w = 0x3f3f3f3f; 9 int main() { 10 memset(g, -1, sizeof(g)); 11 cin >> n >> m; 12 for(int i = 0; i < m; i++) { 13 int u, v, w; 14 cin >> u >> v >> w; 15 g[u][v] = w; 16 g[v][u] = w; 17 } 18 cin >> k; 19 for(int i = 1; i <= k; i++) { 20 memset(vis, false, sizeof(vis)); 21 cin >> nk; 22 bool flag = true; 23 for(int j = 1; j <= nk; j++) { 24 cin >> V[j]; 25 vis[V[j]] = true; 26 } 27 V[0] = V[nk+1] = 0; 28 if(nk != n) { 29 continue; 30 } 31 for(int j = 1; j <= nk; j++) { 32 if(!vis[j]) { 33 flag = false; 34 break; 35 } 36 } 37 if(!flag) { 38 continue; 39 } 40 int sumw = 0; 41 for(int j = 0; j <= nk; j++) { 42 if(g[V[j]][V[j+1]] > 0) { 43 sumw += g[V[j]][V[j+1]]; 44 } else { 45 flag = false; 46 break; 47 } 48 } 49 if(!flag) { 50 continue; 51 } 52 cnt++; 53 if(ans_w > sumw) { 54 ans_w = sumw; 55 ans_i = i; 56 } 57 } 58 cout << cnt << endl; 59 cout << ans_i << " " << ans_w << endl; 60 61 return 0; 62 }