2020.11.28 2020團體程序設計天梯賽補題報告


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 天才能再次申請;
  在上面兩條都符合的情況下,按照提交時間的先后順序發放,直至全部記錄處理完畢或 S​i個名額用完。如果提交時間相同,則按照在列表中出現的先后順序決定。
輸出格式:
對於每一天的申請記錄,每行輸出一位得到口罩的人的姓名及身份證號,用一個空格隔開。順序按照發放順序確定。在輸出完發放記錄后,你還需要輸出有合法記錄的、身體狀況為 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 }
View Code

 

 

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 }
View Code

 

 

L2-4 網紅點打卡攻略 (25分)

 1.題意

  大家來網紅點游玩,俗稱“打卡”。在各個網紅點打卡的方法稱為“攻略”。你的任務就是從一大堆攻略中,找出那個能在每個網紅點打卡僅一次、並且路上花費最少的攻略。

 輸入格式:

首先第一行給出兩個正整數:網紅點的個數 N和網紅點之間通路的條數 M。隨后 M 行,每行給出有通路的兩個網紅點、以及這條路上的旅行花費(為正整數),格式為“網紅點1 網紅點2 費用”,其中網紅點從 1 到 N 編號;同時也給出你家到某些網紅點的花費,格式相同,其中你家的編號固定為 0。再下一行給出一個正整數 K,是待檢驗的攻略的數量。隨后 K 行,每行給出一條待檢攻略,格式為:n V​1 V​2 ⋯ V​n,其中 n是攻略中的網紅點數,V​i是路徑上的網紅點編號。這里假設你從家里出發,從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 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM