算法训练二(字符串、模式匹配、堆栈、队列)(含解题思路)(下)

目录

7-14 出栈序列的合法性

AC代码:

7-15 插松枝

AC代码:

7-16 列车厢调度

AC代码:

7-17 盲盒包装流水线

AC代码:

7-18 特殊堆栈

AC代码:

7-21 队列模拟

AC代码:

7-22 列车调度

AC代码:

7-23 银行业务队列简单模拟

AC代码:

7-24 银行排队问题之单队列多窗口服务

AC代码:

7-26 特殊队列

AC代码:

7-27 软硬车厢交替排列

AC代码:


因题集题目较多,上半部分请移步这里:

算法训练二(字符串、模式匹配、堆栈、队列)(上)_清晨喝碗粥的博客-CSDN博客

7-14 出栈序列的合法性

给定一个最大容量为 M 的堆栈,将 N 个数字按 1, 2, 3, ..., N 的顺序入栈,允许按任何顺序出栈,则哪些数字序列是不可能得到的?例如给定 M=5、N=7,则我们有可能得到{ 1, 2, 3, 4, 5, 6, 7 },但不可能得到{ 3, 2, 1, 7, 5, 6, 4 }。

输入格式:

输入第一行给出 3 个不超过 1000 的正整数:M(堆栈最大容量)、N(入栈元素个数)、K(待检查的出栈序列个数)。最后 K 行,每行给出 N 个数字的出栈序列。所有同行数字以空格间隔。

输出格式:

对每一行出栈序列,如果其的确是有可能得到的合法序列,就在一行中输出YES,否则输出NO

输入样例:

5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2

输出样例:

YES
NO
NO
YES
NO

思路:

这里我们可以定义一个指针item指向数字1,我们对当前序列进行遍历,如果遍历的数字大于等于item,我们将范围区间[item, 遍历的数字]依次入栈,此时item也相应的自加,在此期间,如果栈内的数字的个数超过了其容量,则不合法。如果遍历的数字小于指针item所指的数字,如果此时栈空或者栈顶数字不等于我们当前所遍历的数字则不合法,然后我们需要对栈内数字进行出栈,直到不相等或栈空为止,直到遍历完毕为止

AC代码:

#include<bits/stdc++.h>
using namespace std;
string solve(vector<int>nums, int m) {
    int i, item = 1;
    stack<int>st;
    for (i = 0; i < nums.size();) {
        if (item <= nums[i]) {
            while (item <= nums[i]) {
                st.push(item);
                item++;
            }
            if (st.size() > m)
                return "NO";
            st.pop();
            i++;            
        } else if (item > nums[i]) {
            if (st.empty() || st.top() != nums[i])
                return "NO";
            while (!st.empty() && st.top() == nums[i]) {
                st.pop();
                i++;
            }
        }
    }
    return "YES";
}
int main()
{
    int i, j, k, n, m;
    cin >> m >> n >> k;
    vector<vector<int>>nums(k, vector<int>(n, 0));
    for (i = 0; i < k; i++) {
        for (j = 0; j < n; j++) {
            cin >> nums[i][j];
        }
    }
    vector<string>res;
    i = 0;
    while (i < k) {
        res.push_back(solve(nums[i], m));
        i++;
    }
    for (i = 0; i < res.size(); i++) {
        cout << res[i] << endl;
    }


    system("pause");
    return 0;
}

7-15 插松枝

人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上,做成大大小小的松枝。他们的工作流程(并不)是这样的:

  • 每人手边有一只小盒子,初始状态为空。
  • 每人面前有用不完的松枝干和一个推送器,每次推送一片随机型号的松针片。
  • 工人首先捡起一根空的松枝干,从小盒子里摸出最上面的一片松针 —— 如果小盒子是空的,就从推送器上取一片松针。将这片松针插到枝干的最下面。
  • 工人在插后面的松针时,需要保证,每一步插到一根非空松枝干上的松针片,不能比前一步插上的松针片大。如果小盒子中最上面的松针满足要求,就取之插好;否则去推送器上取一片。如果推送器上拿到的仍然不满足要求,就把拿到的这片堆放到小盒子里,继续去推送器上取下一片。注意这里假设小盒子里的松针片是按放入的顺序堆叠起来的,工人每次只能取出最上面(即最后放入)的一片。
  • 当下列三种情况之一发生时,工人会结束手里的松枝制作,开始做下一个:

(1)小盒子已经满了,但推送器上取到的松针仍然不满足要求。此时将手中的松枝放到成品篮里,推送器上取到的松针压回推送器,开始下一根松枝的制作。

(2)小盒子中最上面的松针不满足要求,但推送器上已经没有松针了。此时将手中的松枝放到成品篮里,开始下一根松枝的制作。

(3)手中的松枝干上已经插满了松针,将之放到成品篮里,开始下一根松枝的制作。

现在给定推送器上顺序传过来的 N 片松针的大小,以及小盒子和松枝的容量,请你编写程序自动列出每根成品松枝的信息。

输入格式:

输入在第一行中给出 3 个正整数:N(≤10^3),为推送器上松针片的数量;M(≤20)为小盒子能存放的松针片的最大数量;K(≤5)为一根松枝干上能插的松针片的最大数量。

随后一行给出 N 个不超过 100 的正整数,为推送器上顺序推出的松针片的大小。

输出格式:

每支松枝成品的信息占一行,顺序给出自底向上每片松针的大小。数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

8 3 4
20 25 15 18 20 18 8 5

输出样例:

20 15
20 18 18 8
25 5

思路:

利用栈对题干的要求进行模拟即可,此题没有坑点

AC代码:

#include<iostream>
using namespace std;
int main()
{
	int i, k, n, m, top, count, temp, max;
	top = -1;
	max = count = 0;
	cin >> n >> m >> k;
	int* a = new int[n];
	int* stack = new int[m];
	for (i = 0; i < n; i++) {
		cin >> a[i];
		if (a[i] > max)
			max = a[i];
	}
	temp = max + 1;
	for (i = 0; i < n;) {
		if (top == m - 1 && a[i] > temp || count == k) {
			count = 0;
			cout << endl;
			temp = max + 1;
		}
		if (top == -1) {
			if (a[i] <= temp) {
				if (count == 0)
					cout << a[i];
				else
					cout << " " << a[i];
				temp = a[i++];
				count++;
			}
			else 
				stack[++top] = a[i++];
		}
		else {
			if (stack[top] <= temp) {
				if (count == 0)
					cout << stack[top];
				else
					cout << " " << stack[top];
				temp = stack[top--];
				count++;
			}
			else {
				if (a[i] <= temp) {
					if (count == 0)
						cout << a[i];
					else
						cout << " " << a[i];
					temp = a[i++];
					count++;
				}
				else
					stack[++top] = a[i++];
			}
		}		
	}
	while (top >= 0) {
		if (stack[top] > temp || count == k) {
			count = 0;
			cout << endl;
			temp = max + 1;
		}
		else {
			if (count == 0)
				cout << stack[top];
			else
				cout << " " << stack[top];
			temp = stack[top--];
			count++;
		}
	}
 
	system("pause");
	return 0;
}

7-16 列车厢调度

        1  ======   <--移动方向
         /
 3 =====  
         \
        2  ======   -->移动方向 

大家或许在某些数据结构教材上见到过“列车厢调度问题”(当然没见过也不要紧)。今天,我们就来实际操作一下列车厢的调度。对照上方的ASCII字符图,问题描述如下:

有三条平行的列车轨道(1、2、3)以及1-3和2-3两段连接轨道。现有一列车厢停在1号轨道上,请利用两条连接轨道以及3号轨道,将车厢按照要求的顺序转移到2号轨道。规则是:

  • 每次转移1节车厢;
  • 处在1号轨道的车厢要么经过1-3连接道进入3号轨道(该操作记为"1->3"),要么经过两条连接轨道直接进入2号轨道(该操作记为"1->2");
  • 一旦车厢进入2号轨道,就不可以再移出该轨道;
  • 处在3号轨道的车厢,只能经过2-3连接道进入2号轨道(该操作记为"3->2");
  • 显然,任何车厢不能穿过、跨越或绕过其它车厢进行移动。

对于给定的1号停车顺序,如果经过调度能够实现2号轨道要求的顺序,则给出操作序列;如果不能,就反问用户 Are(你) you(是) kidding(凯丁) me(么)?

输入格式:

两行由大写字母组成的非空字符串,第一行表示停在1号轨道上的车厢从左到右的顺序,第二行表示要求车厢停到2号轨道的进道顺序(输入样例1中第二行CBA表示车厢在2号轨道的停放从左到右是ABC,因为C最先进入,所以在最右边)。两行字符串长度相同且不超过26(因为只有26个大写字母),每个字母表示一节车厢。题目保证同一行内的字母不重复且两行的字母集相同。

输出格式:

如果能够成功调度,给出最短的操作序列,每个操作占一行。所谓“最短”,即如果1->2可以完成的调度,就不要通过1->3和3->2来实现。如果不能调度,输出 "Are you kidding me?"

输入样例1:

ABC
CBA

输出样例1:

1->3
1->3
1->2
3->2
3->2

输入样例2:

ABC
CAB

输出样例2:

Are you kidding me?

思路:

我们可以建立一个栈来模拟三号铁路,遍历1号铁路,我们将其进行依次比对,如果此时遍历的字母不可以放到2号铁路的末尾则放入3号铁路,如果3号铁路的栈顶不能放到2号铁路的末尾,则输出“Are you kidding me?”,其他情况则将其放到2号铁路即可

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, cur;
    string s, ans;
    cin >> s >> ans;
    stack<char>st3;
    vector<string>res;
    i = cur = 0;
    while (i < ans.length()) {
        if (cur < s.length() && ans[i] == s[cur] || !st3.empty() && st3.top() == ans[i]) {
            while (cur < s.length() && i < ans.length() && ans[i] == s[cur]) {
                res.push_back("1->2");
                i++;
                cur++;
            }
            while (!st3.empty() && st3.top() == ans[i]) {
                res.push_back("3->2");
                i++;
                st3.pop();
            }              
        } else {
            if (cur < s.length()) {
                while (cur < s.length() && ans[i] != s[cur]) {
                    res.push_back("1->3");
                    st3.push(s[cur]);
                    cur++;
                }                
            } else {
                cout << "Are you kidding me?" << endl;
                return 0;
            }
        }
    }
    for (i = 0; i < res.size(); i++) {
        cout << res[i] << endl;
    }

    system("pause");
    return 0;
}

7-17 盲盒包装流水线

众所周知,PAT 有 9 枚徽章,分别对应青铜、白银、黄金、白金、钻石、大师、王者、大圣、天神这 9 个段位,只有成绩非常优秀的考生才有资格获得刻有自己名字的徽章。现在,PAT 制作了徽章的小型纪念版,要制成盲盒给大家玩了!

下图是一条盲盒包装流水线的示意图。首先徽章通过进货口被压入货栈里,空盒在履带上从左向右传送。每次从货栈里弹出一枚徽章,进入打包机,装入一只空盒,打包后继续向右边传送。当货栈为空时,打包机会暂停,等待下一批徽章压入货栈。

 每只盒子都有一个编号,小拼姐姐手里有进入流水线的空盒编号顺序表,也有每一批送往货栈的徽章顺序表,这样她其实可以知道每只盒子里装了哪种徽章。有些小朋友收到了盲盒,就想在拆封前问无所不知的小拼姐姐,盒子里的徽章是哪一种。但是因为盲盒总量有 10^5 这么多,小拼姐姐可记不住每只盒子里装的是什么,于是你就被请来写个程序帮小拼姐姐回复这种信息。

输入格式:

输入第一行给出 2 个正整数,分别为盲盒总量 N(≤10^5)和货栈容量 S(≤100)。接下来一行给出 N 只盒子的编号,编号由 5 位数字组成,给出的顺序是空盒进入传送带的顺序。随后 N/S(保证是整数)行,每行给出一批 S 枚徽章的类型,为 1-9 的数字,给出的顺序是从进货口入栈的顺序。

再下面给出一个正整数 K(≤10^4),为查询次数。随后 K 行,每行给出一个 5 位编号。

输出格式:

对每个查询编号,在一行中输出该盒子中装的徽章类型。如果编号是错误的,则在一行中输出 Wrong Number

输入样例:

10 5
00132 10093 92001 23333 66666 88888 09009 34658 82750 69251
1 2 3 4 5
9 8 7 6 1
5
66666
88888
69251
55555
10093

输出样例:

1
1
9
Wrong Number
4

思路:

此题为模拟题,我们可以定义一个map来记录每个盲盒里存放的徽章,最后对其进行查询即可

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, j, k, n, s, cur = 0;
    cin >> n >> s;
    vector<int>nums(n, 0);
    map<int, int>consult;
    vector<vector<int>>item(n / s, vector<int>(s, 0));
    stack<int>st;
    for (i = 0; i < n; i++) {
        cin >> nums[i];
    }
    for (i = 0; i < n / s; i++) {
        for (j = 0; j < s; j++) {
            cin >> item[i][j];
        }
    }
    for (i = 0; i < n; i++) {
        if (st.empty() && cur < n / s) {
            for (j = 0; j < s; j++) {
                st.push(item[cur][j]);
            }
            cur++;
        }
        consult[nums[i]] = st.top();
        st.pop();
    }
    cin >> k;
    vector<int>arr(k, 0);
    for (i = 0; i < k; i++) {
        cin >> arr[i];
    }
    for (i = 0; i < k; i++) {
        if (consult.find(arr[i]) == consult.end())
            cout << "Wrong Number" << endl;
        else
            cout << consult[arr[i]] << endl;
    }



    system("pause");
    return 0;
}

7-18 特殊堆栈

堆栈是一种经典的后进先出的线性结构,相关的操作主要有“入栈”(在堆栈顶插入一个元素)和“出栈”(将栈顶元素返回并从堆栈中删除)。本题要求你实现另一个附加的操作:“取中值”——即返回所有堆栈中元素键值的中值。给定 N 个元素,如果 N 是偶数,则中值定义为第 N/2 小元;若是奇数,则为第 (N+1)/2 小元。

输入格式:

输入的第一行是正整数 N(≤10^5)。随后 N 行,每行给出一句指令,为以下 3 种之一:

Push key
Pop
PeekMedian

其中 key 是不超过 10^5 的正整数;Push 表示“入栈”;Pop 表示“出栈”;PeekMedian 表示“取中值”。

输出格式:

对每个 Push 操作,将 key 插入堆栈,无需输出;对每个 Pop 或 PeekMedian 操作,在一行中输出相应的返回值。若操作非法,则对应输出 Invalid

输入样例:

17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop

输出样例:

Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid

思路:

这里着重讲一下取中值,我们可以建立一个树状数组,假设我们要寻找第x小的数,所以我们可以利用sum(i)函数来求其前缀和,因为i不一定在栈里,所以我们的思路就转化为了在sum(i) >= x的条件下求得的sum(i)中最小的i就是其最终结果,所以我们可以利用二分查找算法来实现

AC代码:

#include<bits/stdc++.h>
using namespace std;
int a[100005];
int lowbit(int i) {   //求i的区间长度
	return (-i) & i;
}
void add(int i, int x) { //点更新,让a[i] + x
	for (i; i < 100000; i += lowbit(i)) {
		a[i] += x;
	}
}
int sum(int i) { //求前缀和
	int sum = 0;
	for (i; i > 0; i -= lowbit(i)) {
		sum += a[i];
	}
	return sum;
}
int main()
{
	int i, j, k, n;
	memset(a, 0, sizeof(a));
	cin >> n;
	vector<pair<string, int>>nums;
	for (i = 0; i < n; i++) {
		string first;
		int second = 0;
		cin >> first;
		if (first == "Push")
			cin >> second;
		nums.push_back(pair<string, int>(first, second));
	}
	stack<int>st;
	for (i = 0; i < nums.size(); i++) {
		if (nums[i].first == "Push") {
			st.push(nums[i].second);
			add(nums[i].second, 1);
		} else if (nums[i].first == "Pop") {
			if (st.empty())
				cout << "Invalid" << endl;
			else {
				cout << st.top() << endl;
				add(st.top(), -1);
				st.pop();
			}
		} else {
			if (st.empty())
				cout << "Invalid" << endl;
			else {
				int x = st.size() % 2 == 0 ? (st.size() / 2) : ((st.size() + 1) / 2);
				int l = 1, r = 100000, mid = (l + r) / 2;
				while (l != r) {
					if (sum(mid) < x)
						l = mid + 1;
					else
						r = mid;
					mid = (l + r) / 2;						
				}
				cout << mid << endl;
			}
		}
	}

	system("pause");
	return 0;
}

7-21 队列模拟

设从键盘输入一整数序列a1,a2,...an,试编程实现:当ai>0 时,ai 进队,当ai<0 时,将队首元素出队,当ai=0 时,表示输入结束。要求将队列处理成环形队列,使用环形队列算法库中定义的数据类型及算法,程序中只包括一个函数(main 函数),入队和出队等操作直接在main 函数中调用即可。当进队出队异常(如队满)时,要打印出错信息。

输入格式:

输入一系列整数,以0结束。环形队列最多可存储10个元素。

输出格式:

输出最后队列中的元素。如果队列满,则显示“队列已满”,如果出队列时无元素可出,显示“wrong”

输入样例1:

1 2 3 -4 -5  6 7 -8 0

输出样例1:

The Queue is:6 7 

输入样例2:

1 2 -4 -5  -6 7 -8 0

输出样例2:

wrong

输入样例3:

1 2 3 4 5  6 7 8 9 10 11 12 0

输出样例3:

Queue is full!
The Queue is:1 2 3 4 5 6 7 8 9 10 

思路:

对于算法竞赛,有现成的queue容器何必要造轮子呢?如果对于不清楚其底层实现方法还是要去了解一下的,这里提供queue容器写法,代码如下

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, j, k, n, x;
    vector<int>nums;
    cin >> x;
    while (x != 0) {
        nums.push_back(x);
        cin >> x;
    }
    queue<int>Q;
    for (i = 0; i < nums.size(); i++) {
        if (nums[i] > 0) {
            if (Q.size() >= 10) {
                cout << "Queue is full!" << endl;
                break;
            }
            Q.push(nums[i]);
        } else if (nums[i] < 0){
            if (Q.empty()) {
                cout << "wrong" << endl;
                return 0;
            }
            Q.pop();
        }
    }
    if (Q.empty())
        cout << "wrong" << endl;
    if (!Q.empty())
        cout << "The Queue is:";
    while (!Q.empty()) {
        cout << Q.front() << " ";
        Q.pop();
    }

    system("pause");
    return 0;
}

7-22 列车调度

火车站的列车调度铁轨的结构如下图所示。

两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度? 

输入格式:

输入第一行给出一个整数N (2 ≤ N ≤10^5),下一行给出从1到N的整数序号的一个重排列。数字间以空格分隔。

输出格式:

在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。

输入样例:

9
8 4 2 5 3 9 1 6 7

输出样例:

4

思路:

这道题我们不难分析出来,如果是第一次进入中间铁轨或着是入口处的数字大于已有的每个铁轨上(从左往右看)第一个数字时我们就要开启一条新的铁轨将其插入进去,否则的话我们就要挑选每个铁轨上与入口数字最接近的那条铁轨将其插入进去,拿图片上的样例为例,最终所需铁轨以及铁轨上的数字如下:

 知道大致原理,这里推荐一个小技巧,我们不用去把每条铁轨上的数字都罗列去存储,我们可以只存每条铁轨最小的那个数字,这里推荐运用set内置的二分算法lower_bound(二分查找一个有序数列,返回第一个大于等于x的数,如果没找到则返回末尾迭代器的位置),我们可以用set内置的二分查找来查找第一个大于等于即将进入铁轨的数,如果找到了则删除这个数,插入新进入铁轨的数(即更新每条铁轨的最小值),否则的话就另开一条新的铁轨将其插入,最终的set的大小就是最少所需铁轨数

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, n;
    cin >> n;
    vector<int>nums(n, 0);
    set<int>Q;
    for (i = 0; i < n; i++) {
        cin >> nums[i];
    }
    for (i = 0; i < n; i++) {
        if (Q.lower_bound(nums[i]) != Q.end())
            Q.erase(Q.lower_bound(nums[i]));
        Q.insert(nums[i]);
    }
    cout << Q.size() << endl;

    system("pause");
    return 0;
}

7-23 银行业务队列简单模拟

设某银行有A、B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客。给定到达银行的顾客序列,请按业务完成的顺序输出顾客序列。假定不考虑顾客先后到达的时间间隔,并且当不同窗口同时处理完2个顾客时,A窗口顾客优先输出。

输入格式:

输入为一行正整数,其中第1个数字N(≤1000)为顾客总数,后面跟着N位顾客的编号。编号为奇数的顾客需要到A窗口办理业务,为偶数的顾客则去B窗口。数字间以空格分隔。

输出格式:

按业务处理完成的顺序输出顾客的编号。数字间以空格分隔,但最后一个编号后不能有多余的空格。

输入样例:

8 2 1 3 9 4 11 13 15

输出样例:

1 3 2 9 11 4 13 15

思路:

简单模拟题,代码具体如下

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, j, k, n;
    cin >> n;
    vector<int>res;
    queue<int>Q1, Q2;
    for (i = 0; i < n; i++) {
        int x;
        cin >> x;
        if (x % 2 == 0)
            Q2.push(x);
        else
            Q1.push(x);
    }
    while (!Q1.empty() || !Q2.empty()) {
        for (i = 0; !Q1.empty() && i < 2; i++) {
            res.push_back(Q1.front());
            Q1.pop();
        }
        if (!Q2.empty()) {
            res.push_back(Q2.front());
            Q2.pop();
        }
    }
    for (i = 0; i < res.size(); i++) {
        if (i == 0)
            cout << res[i];
        else
            cout << " " << res[i];
    }

    system("pause");
    return 0;
}

7-24 银行排队问题之单队列多窗口服务

假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。

本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。

输入格式:

输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间T和事务处理时间P,并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10),为开设的营业窗口数。这里假设每位顾客事务被处理的最长时间为60分钟。

输出格式:

在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。

在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。

输入样例:

9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3

输出样例:

6.2 17 61
5 3 1

思路:

本题为略微复杂一点的模拟题,文字描述可能不太好理解,可以结合这位博主的题解

PTA 7-3 银行排队问题之单队列多窗口服务_北极光。的博客-CSDN博客

进行理解模拟,以下是我的代码

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, j, k, n, long_time = 0, res_time = 0;
    double ave_time = 0;
    cin >> n;
    queue<pair<int, int>>Q;
    for (i = 0; i < n; i++) {
        int first, second;
        cin >> first >> second;
        second = second > 60 ? 60 : second;
        Q.push(pair<int, int>(first, second));
    }
    cin >> k;
    vector<vector<int>>nums(k, vector<int>(2, 0));
    while (!Q.empty()) {
        bool flag = false;
        int index = 0, minn = INT_MAX;
        for (i = 0; i < nums.size(); i++) {
            if (nums[i][0] <= Q.front().first) {
                nums[i][0] = Q.front().second + Q.front().first;
                nums[i][1]++;
                Q.pop();
                flag = true;
                break;
            }
            if (minn > nums[i][0]) {
                index = i;
                minn = nums[i][0];
            }
        }
        if (!flag) {
            long_time = max(long_time, nums[index][0] - Q.front().first);
            ave_time += nums[index][0] - Q.front().first;
            nums[index][0] += Q.front().second;
            nums[index][1]++;
            Q.pop();
        }
    }


    for (i = 0; i < nums.size(); i++) {
        res_time = max(res_time, nums[i][0]);
    }
    ave_time = ave_time * 1.0 / n;
    printf("%.1lf %d %d\n", ave_time, long_time, res_time);
    for (i = 0; i < nums.size(); i++) {
        if (i == 0)
            cout << nums[i][1];
        else
            cout << " " << nums[i][1];
    }


    system("pause");
    return 0;
}

7-26 特殊队列

普通的队列仅有 EnQueue 和 DeQueue 两种操作,分别表示在队尾增加元素和取出队首元素。现在给队列增加一种新的操作 DeleteMid,表示删除队列的中间元素。对于有 N 个元素的队列,若 N 为偶数,中间元素定义为从队首到队尾的第 N/2 个元素;若 N 为奇数,中间元素定义为第 (N+1)/2 个元素。现给出队列的一系列操作,输出相应结果。

输入格式:

第一行输入一个不超过 106 的正整数 M 和 N,分别表示指令条数和队列容量。

之后 M 行,每行给出一条指令,为下列3种指令之一:

EnQueue elem

DeQueue

DeleteMid

输出格式:

对于每个 EnQueue 指令,若未超出队列容量,不输出任何信息,否则在一行中输出Full Queue

对于每个 DeQueue 和 DeleteMid 指令,若队列不为空,则取出相应元素并输出;否则只在一行中输出Empty Queue

最后在一行中按从队首到队尾的顺序依次输出队列中的元素,以空格分隔。行尾不得有多余空格。

输入样例:

10 4
DeQueue
EnQueue 2
EnQueue 3
EnQueue 4
EnQueue 5
DeleteMid
DeleteMid
EnQueue 7
EnQueue 8
EnQueue 9

输出样例:

Empty Queue
3
4
Full Queue
2 5 7 8

思路:

这里我就不得不推荐下学长的思路,在这贴一下他的题解:

pta 特殊队列 (30分)_海马有力量的博客-CSDN博客_普通的队列仅有 enqueue 和 dequeue 两种操作,分别表示在队尾增加元素和取出队首

以下是我按他的思路写的代码

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, j, k, n, m;
    deque<int>Q1, Q2;
    scanf("%d %d", &m, &n);
    vector<pair<string, int>>nums;
    for (i = 0; i < m; ++i) {
        string first;
        int second = 0;
        cin >> first;
        if (first == "EnQueue")
            scanf("%d", &second);
        nums.push_back(pair<string, int>(first, second));
    }
    for (i = 0; i < m; ++i) {
        if (nums[i].first == "EnQueue") {
            if (Q1.size() + Q2.size() >= n)
                printf("Full Queue\n");
            else
                Q2.push_back(nums[i].second);
        } else if (nums[i].first == "DeQueue") {
            if (Q1.empty())
                printf("Empty Queue\n");
            else {
                printf("%d\n", Q1.front());
                Q1.pop_front();
            }
        } else {
            if (Q1.empty())
                printf("Empty Queue\n");
            else {
                printf("%d\n", Q1.back());
                Q1.pop_back();
            }
        }
        while (Q2.size() > Q1.size()) {
            Q1.push_back(Q2.front());
            Q2.pop_front();
        }         
    }
    bool flag = true;
    while (!Q1.empty()) {
        if (flag)
            printf("%d", Q1.front());
        else
            printf(" %d", Q1.front());
        flag = false;
        Q1.pop_front();
    }
    while (!Q2.empty()) {
        if (flag)
            printf("%d", Q2.front());
        else
            printf(" %d", Q2.front());
        flag = false;
        Q2.pop_front();
    }

    system("pause");
    return 0;
}

7-27 软硬车厢交替排列

设车辆厂生产了硬座车厢和软座车厢共n节(混合在一起),要求使用队列的基本操作,编程实现所有硬座车厢和所有软座车厢交替排列。例如硬座车厢用H来表示,软座车厢用S来表示,从键盘上输入8节车厢代号为SHHSSHSS ,输出为HSHSHSSS。若从键盘输入8节车厢代号为SHHSHHSH ,输出为HSHSHSHH。

输入格式:

第一行输入硬座和软座车厢共有的节数,2<=节数<=10;
第二行按节数输入车厢代号。

输出格式:

若车厢节数超出合法范围,输出“ERROR”,否则输出H和S车厢交替排列结果,注意输出结果以H开头。

输入样例:

8
SHHSSHSS

输出样例:

HSHSHSSS

思路:

简单模拟,可以用两个队列分别保存软座车厢和硬座车厢,最后一个while循环交替输出即可

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i, j, k, n;
    cin >> n;
    if (n < 2 || n > 10) {
        cout << "ERROR" << endl;
        return 0;
    }
    string s, res = "";
    queue<char>Q1, Q2;
    cin >> s;
    for (i = 0; i < s.length(); i++) {
        if (s[i] == 'H')
            Q1.push(s[i]);
        else
            Q2.push(s[i]);
    }
    while (!Q1.empty() || !Q2.empty()) {
        if (!Q1.empty()) {
            res += Q1.front();
            Q1.pop();
        }
        if (!Q2.empty()) {
            res += Q2.front();
            Q2.pop();
        }
    }
    cout << res << endl;

    system("pause");
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值