PAT练习笔记——13.3 快乐模拟

2019年9月PAT - 练习笔记——13.3

以下页码标注的是阅读器中实际页码,而不是书本身自印的页码。

第13章 提高篇(6)——专题扩展

13.3 快乐模拟

看到“模拟”这两个字我就一点都不快乐了

目录

  1. B1050 / A1105 螺旋矩阵
  2. A1017 Queueing at Bank
  3. A1014 Waiting in Line
  4. A1026 Table Tennis

  1. B1050 / A1105 螺旋矩阵

    本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 mn 列,满足条件:m×n 等于 Nmn;且 mn 取所有可能值中的最小值。

    输入格式:

    输入在第 1 行中给出一个正整数 N,第 2 行给出 N 个待填充的正整数。所有数字不超过 104,相邻数字以空格分隔。

    输出格式:

    输出螺旋矩阵。每行 n 个数字,共 m 行。相邻数字以 1 个空格分隔,行末不得有多余空格。

    输入样例:
    12
    37 76 20 98 76 42 53 95 60 81 58 93
    
    输出样例:
    98 95 93
    42 37 81
    53 20 76
    58 60 76
    
    1. 我的

      #include <iostream>
      #include <vector>
      #include <cmath>
      #include <algorithm>
      
      using namespace std;
      
      int main(void)
      {
      	int N = 0;
      	scanf("%d", &N);
      	vector<int> nums(N, 0);
      	for (int i = 0;i < N;++i) scanf("%d", &nums[i]); 
      	sort(nums.begin(), nums.end(), greater<int>());
      	
      	int m = N, n = 1, sqr = sqrt(N);
      	for (int n = 2;n <= sqr;++n) {
      		if (0 == N % n) m = N / n;
      	}
      	n = N / m;
      	
      	vector<vector<int>> matrix(m, vector<int>(n, 0));
      	int i = 0, j = 0, d = 0;
      	const int di[] = {0, 1, 0, -1}, dj[] = {1, 0, -1, 0};
      	for (int count = 0;count < N;) {
      		for (;count < N && 0 <= i && i < m && 0 <= j && j < n && !matrix[i][j];) {
      			matrix[i][j] = nums[count++];
      			i += di[d], j += dj[d];
      		}
      		i -= di[d], j -= dj[d];
      		d = (d + 1) % 4;
      		i += di[d], j += dj[d];
      	}
      	for (int i = 0;i < m;++i) {
      		printf("%d", matrix[i][0]);
      		for (int j = 1;j < n;++j) printf(" %d", matrix[i][j]);
      		printf("\n");
      	}
      	
      	return 0;
      } 
      
    2. 《算法笔记》P416

      “……让m从根号N(向上取整)开始不断递增,直到N % m == 0为止”


  2. A1017 Queueing at Bank

    Suppose a bank has K windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. All the customers have to wait in line behind the yellow line, until it is his/her turn to be served and there is a window available. It is assumed that no window can be occupied by a single customer for more than 1 hour.

    Now given the arriving time T and the processing time P of each customer, you are supposed to tell the average waiting time of all the customers.

    Input Specification:

    Each input file contains one test case. For each case, the first line contains 2 numbers: N (≤104) - the total number of customers, and K (≤100) - the number of windows. Then N lines follow, each contains 2 times: HH:MM:SS - the arriving time, and P - the processing time in minutes of a customer. Here HH is in the range [00, 23], MM and SS are both in [00, 59]. It is assumed that no two customers arrives at the same time.

    Notice that the bank opens from 08:00 to 17:00. Anyone arrives early will have to wait in line till 08:00, and anyone comes too late (at or after 17:00:01) will not be served nor counted into the average.

    Output Specification:

    For each test case, print in one line the average waiting time of all the customers, in minutes and accurate up to 1 decimal place.

    Sample Input:
    7 3
    07:55:00 16
    17:00:01 2
    07:59:59 15
    08:01:00 60
    08:00:00 30
    08:00:02 2
    08:03:00 10
    
    Sample Output:
    8.2
    
    1. 我的

      #include <iostream>
      #include <vector>
      #include <string>
      #include <queue>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	int n = 0, k = 0;
      	scanf("%d %d", &n, &k);
      	
      	int start = 8 * 3600, end = 17 * 3600, MAX = 3600;
      	priority_queue<int, vector<int>, greater<int>> arrive;
      	map<int, int> process;
      	
      	string t = "";
      	int p = 0;
      	for (int i = 0;i < n;++i) {
      		cin >> t >> p;
      		int h = 0, m = 0, s = 0;
      		sscanf(t.c_str(), "%d:%d:%d", &h, &m, &s);
      		int period = h *3600 + m * 60 + s;
      		if (period <= end) {
      			arrive.push(period);
      			process[period] = min(p, 60) * 60;
      		}
      	}
      	
      	int wait = 0;
      	vector<int> windows(k, 0);
      	for (int i = 0;i < k && !arrive.empty();++i) {
      		int time = arrive.top();
      		if (time < start) {
      			wait += start - time;
      			windows[i] = start + process[time];
      		}
      		else windows[i] = time + process[time];
      		arrive.pop();
      	}
      	for (;!arrive.empty();) {
      		int MIN = 0;
      		for (int i = 1;i < k;++i) {
      			if (windows[i] < windows[MIN]) MIN = i;
      		}
      		int time = arrive.top();
      		if (time < windows[MIN]) {
      			wait += windows[MIN] - time;
      			windows[MIN] += process[time];
      		}
      		else windows[MIN] = time + process[time];
      		arrive.pop();
      	}
      	
      	printf("%.1f", (float)wait / 60 / process.size());
      	
      	return 0;
      } 
      

      上次做的超差,这次挺顺的还一遍过,看得到自己的进步真的超级快乐!

    2. 《算法笔记》P419

      ”如果在17:00:00前到达的客户数为0,那么应当直接输出0.0,但是本题数据中没有体现这一点,故可以不处理。“


  3. A1014 Waiting in Line

    Suppose a bank has N windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. The rules for the customers to wait in line are:

    • The space inside the yellow line in front of each window is enough to contain a line with M customers. Hence when all the N lines are full, all the customers after (and including) the (NM+1)st one will have to wait in a line behind the yellow line.
    • Each customer will choose the shortest line to wait in when crossing the yellow line. If there are two or more lines with the same length, the customer will always choose the window with the smallest number.
    • Customeri will take Ti minutes to have his/her transaction processed.
    • The first N customers are assumed to be served at 8:00am.

    Now given the processing time of each customer, you are supposed to tell the exact time at which a customer has his/her business done.

    For example, suppose that a bank has 2 windows and each window may have 2 custmers waiting inside the yellow line. There are 5 customers waiting with transactions taking 1, 2, 6, 4 and 3 minutes, respectively. At 08:00 in the morning, customer1 is served at window1 while customer2 is served at window2. Customer3 will wait in front of window1 and customer4 will wait in front of window2. Customer5 will wait behind the yellow line.

    At 08:01, customer1 is done and customer5 enters the line in front of window1 since that line seems shorter now. Customer2 will leave at 08:02, customer4 at 08:06, customer3 at 08:07, and finally customer5 at 08:10.

    Input Specification:

    Each input file contains one test case. Each case starts with a line containing 4 positive integers: N (≤20, number of windows), M (≤10, the maximum capacity of each line inside the yellow line), K (≤1000, number of customers), and Q (≤1000, number of customer queries).

    The next line contains K positive integers, which are the processing time of the K customers.

    The last line contains Q positive integers, which represent the customers who are asking about the time they can have their transactions done. The customers are numbered from 1 to K.

    Output Specification:

    For each of the Q customers, print in one line the time at which his/her transaction is finished, in the format HH:MM where HH is in [08, 17] and MM is in [00, 59]. Note that since the bank is closed everyday after 17:00, for those customers who cannot be served before 17:00, you must output Sorry instead.

    Sample Input:
    2 2 7 5
    1 2 6 4 3 534 2
    3 4 5 6 7
    
    Sample Output:
    08:07
    08:06
    08:10
    17:00
    Sorry
    
    1. 我的

      #include <iostream>
      #include <vector>
      #include <queue>
      
      using namespace std;
      
      int main(void)
      {
      	int n = 0, m = 0, k = 0, q = 0;
      	scanf("%d %d %d %d", &n, &m, &k, &q);
      	
      	vector<int> process(k + 1, 0);
      	for (int i = 1;i <= k;++i) scanf("%d", &process[i]);
      	
      	int start = 8 * 60, end = 17 * 60;
      	vector<int> windows(n, start), done(k + 1, 0);
      	vector<queue<int>> line(n);
      	int customer = 1;
      	for (int i = 0;i < n && customer <= k;++i) {
      		windows[i] += process[customer];
      		done[customer] = windows[i];
      		line[i].push(customer);
      		++customer;
      	}
      	for (int j = 1;j < m;++j) {
      		for (int i = 0;i < n && customer <= k;++i) {
      			line[i].push(customer);
      			++customer;
      		}
      	}
      	
      	for (int i = n + 1;i <= k;) {
      		int MIN = 0;
      		for (;MIN < n && line[MIN].empty();++MIN);
      		for (int j = MIN + 1;j < n;++j) {
      			if (!line[j].empty() && windows[j] < windows[MIN]) MIN = j;
      		}
      		if (windows[MIN] >= end) break;
      		
      		if (customer <= k) {
      			line[MIN].push(customer);
      			++customer;
      		}
      		line[MIN].pop();
      		if (!line[MIN].empty()) {
      			int now = line[MIN].front();
      			windows[MIN] += process[now];
      			done[now] = windows[MIN];
      			++i;
      		}
      	}
      	
      	for (;q;q--) {
      		int query = 0;
      		scanf("%d", &query);
      		if (!done[query]) printf("Sorry\n");
      		else printf("%02d:%02d\n", done[query] / 60, done[query] % 60);
      	}
      	
      	return 0;
      } 
      

      测试点3一直答案错误,网上翻半天也没发现和我一样错这个点的,自己试出来了

      // 测试用例1
      2 1 3 3
      100 1 1
      1 2 3
      // 测试用例2
      2 2 3 3
      100 1 100
      1 2 3
      
      1. 注意m=1的情况
        1. 有些解析说要注意m=0的情况,但其实题目已经说了m是正整数
      2. 注意某个窗口为空时,但其它窗口队列除了在服务的人之外还有人在排队的情况
    2. 《算法笔记》P423


  4. A1026 Table Tennis

    A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For any pair of players, if there are some tables open when they arrive, they will be assigned to the available table with the smallest number. If all the tables are occupied, they will have to wait in a queue. It is assumed that every pair of players can play for at most 2 hours.

    Your job is to count for everyone in queue their waiting time, and for each table the number of players it has served for the day.

    One thing that makes this procedure a bit complicated is that the club reserves some tables for their VIP members. When a VIP table is open, the first VIP pair in the queue will have the priviledge to take it. However, if there is no VIP in the queue, the next pair of players can take it. On the other hand, if when it is the turn of a VIP pair, yet no VIP table is available, they can be assigned as any ordinary players.

    Input Specification:

    Each input file contains one test case. For each case, the first line contains an integer N (≤10000) - the total number of pairs of players. Then N lines follow, each contains 2 times and a VIP tag: HH:MM:SS - the arriving time, P - the playing time in minutes of a pair of players, and tag - which is 1 if they hold a VIP card, or 0 if not. It is guaranteed that the arriving time is between 08:00:00 and 21:00:00 while the club is open. It is assumed that no two customers arrives at the same time. Following the players’ info, there are 2 positive integers: K (≤100) - the number of tables, and M (< K) - the number of VIP tables. The last line contains M table numbers.

    Output Specification:

    For each test case, first print the arriving time, serving time and the waiting time for each pair of players in the format shown by the sample. Then print in a line the number of players served by each table. Notice that the output must be listed in chronological order of the serving time. The waiting time must be rounded up to an integer minute(s). If one cannot get a table before the closing time, their information must NOT be printed.

    Sample Input:
    9
    20:52:00 10 0
    08:00:00 20 0
    08:02:00 30 0
    20:51:00 10 0
    08:10:00 5 0
    08:12:00 10 1
    20:50:00 10 0
    08:01:30 15 1
    20:53:00 10 1
    3 1
    2
    
    Sample Output:
    08:00:00 08:00:00 0
    08:01:30 08:01:30 0
    08:02:00 08:02:00 0
    08:12:00 08:16:30 5
    08:10:00 08:20:00 10
    20:50:00 20:50:00 0
    20:51:00 20:51:00 0
    20:52:00 20:52:00 0
    3 3 2
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <vector>
      #include <queue>
      #include <map>
      #include <cmath>
      
      using namespace std;
      
      int main(void)
      {
      	int n = 0;
      	scanf("%d", &n);
      	
      	string time = "";
      	int period = 0;
      	int tag = 0;
      	priority_queue<int, vector<int>, greater<int>> ordinary, vips;
      	map<int, int> periods;
      	for (int i = 0;i < n;++i) {
      		cin >> time >> period >> tag;
      		int h = 0, m = 0, s = 0;
      		sscanf(time.c_str(), "%d:%d:%d", &h, &m, &s);
      		int arrive = h * 3600 + m * 60 + s;
      		
      		periods[arrive] = min(120, period) * 60;
      		if (tag) vips.push(arrive);
      		else ordinary.push(arrive);
      	}
      	
      	int k = 0, m = 0;
      	scanf("%d %d", &k, &m);
      	vector<bool> flags(k + 1, false);
      	for (int i = 0;i < m;++i) {
      		int vip = 0;
      		scanf("%d", &vip);
      		flags[vip] = true;
      	}
      	
      	int start = 8 * 3600, end = 21 * 3600;
      	vector<int> tableTime(k + 1, start), tableAmount(k + 1, 0);
      	for (;!ordinary.empty() || !vips.empty();) {
      		int MIN = 1, MINvip = 0;
      		for (int i = 2;i <= k;++i) {
      			if (tableTime[i] < tableTime[MIN]) MIN = i;
      		}
      		for (int i = 1;i <= k;++i) {
      			if (flags[i] && tableTime[i] == tableTime[MIN]) MINvip = i;
      		}
      		if (tableTime[MIN] >= end) break;
      		
      		int arrive = 0;
      		if (MINvip && !vips.empty()) {
      			if (tableTime[MINvip] >= vips.top() || ordinary.empty() || vips.top() < ordinary.top()) {
      				arrive = vips.top();
      				vips.pop();
      				MIN = MINvip;
      			}
      		}
      		if (!arrive) {
      			if (vips.empty() || (!ordinary.empty() && vips.top() > ordinary.top())) {
      				arrive = ordinary.top();
      				ordinary.pop();
      			}
      			else {
      				arrive = vips.top();
      				vips.pop();
      			}
      		}
      		if (arrive >= end) break;
      		
      		int wait = 0;
      		int h1 = arrive / 3600, m1 = (arrive % 3600) / 60, s1 = arrive % 60;
      		int h2 = h1, m2 = m1, s2 = s1;
      		if (tableTime[MIN] > arrive) {
      			h2 = tableTime[MIN] / 3600, m2 = (tableTime[MIN] % 3600) / 60, s2 = tableTime[MIN] % 60;
      			wait = tableTime[MIN] - arrive;
      			tableTime[MIN] += periods[arrive];
      		}
      		else tableTime[MIN] = arrive + periods[arrive];
      		++tableAmount[MIN];
      		int waitn = round(wait / 60.);
      		printf("%02d:%02d:%02d %02d:%02d:%02d %d\n", h1, m1, s1, h2, m2, s2, waitn);
      	}
      	
      	printf("%d", tableAmount[1]);
      	for (int i = 2;i <= k;++i) printf(" %d", tableAmount[i]);
      	
      	return 0;
      } 
      

      测试点4:不能超过2小时

      题意关于vip这一块要仔细理解。vip来的时候既有vip桌又有序号更小的非vip桌,依然把vip桌分给vip

      之前这一题一直没做出来,留下很深的阴影,导致我看到模拟题就产生畏惧心理。现在做完觉得就还好啊,之前真是太菜了orz

    2. 《算法笔记》P428


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值