7-1 Windows消息队列
分数 25
全屏浏览题目
切换布局
作者 DS课程组
单位 浙江大学
消息队列是Windows系统的基础。对于每个进程,系统维护一个消息队列。如果在进程中有特定事件发生,如点击鼠标、文字改变等,系统将把这个消息加到队列当中。同时,如果队列不是空的,这一进程循环地从队列中按照优先级获取消息。请注意优先级值低意味着优先级高。请编辑程序模拟消息队列,将消息加到队列中以及从队列中获取消息。
输入格式:
输入首先给出正整数N(≤105),随后N行,每行给出一个指令——GET
或PUT
,分别表示从队列中取出消息或将消息添加到队列中。如果指令是PUT
,后面就有一个消息名称、以及一个正整数表示消息的优先级,此数越小表示优先级越高。消息名称是长度不超过10个字符且不含空格的字符串;题目保证队列中消息的优先级无重复,且输入至少有一个GET
。
输出格式:
对于每个GET
指令,在一行中输出消息队列中优先级最高的消息的名称和参数。如果消息队列中没有消息,输出EMPTY QUEUE!
。对于PUT
指令则没有输出。
输入样例:
9
PUT msg1 5
PUT msg2 4
GET
PUT msg3 2
PUT msg4 4
GET
GET
GET
GET
输出样例:
msg2
msg3
msg4
msg1
EMPTY QUEUE!
#include <iostream>
#include <queue>
#include <string>
using namespace std;
struct node
{
char message[11];
int rank;
friend bool operator<(node a, node b)
{
return a.rank > b.rank;
}
};
priority_queue<node> q;
int main()
{
string op;
node p;
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
cin >> op;
if (op[0] == 'P')
{
cin >> p.message >> p.rank;
//printf("%s %s", p.message, p.rank);
q.push(p);
}
else if (op[0] == 'G')
{
if (q.empty())
printf("EMPTY QUEUE!\n");
else
{
printf("%s\n", q.top().message);
q.pop();
}
}
}
return 0;
}
7-2 笛卡尔树
分数 25
全屏浏览题目
切换布局
作者 DS课程组
单位 浙江大学
笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2。首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树则大。其次所有结点的K2关键字满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中所有结点的K2值小。给定一棵二叉树,请判断该树是否笛卡尔树。
输入格式:
输入首先给出正整数N(≤1000),为树中结点的个数。随后N行,每行给出一个结点的信息,包括:结点的K1值、K2值、左孩子结点编号、右孩子结点编号。设结点从0~(N-1)顺序编号。若某结点不存在孩子结点,则该位置给出−1。
输出格式:
输出YES
如果该树是一棵笛卡尔树;否则输出NO
。
输入样例1:
6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 21 -1 4
15 22 -1 -1
5 35 -1 -1
输出样例1:
YES
输入样例2:
6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 11 -1 4
15 22 -1 -1
50 35 -1 -1
输出样例2:
NO
#include <bits/stdc++.h>
using namespace std;
int n;
struct tree
{
int k1, k2;
int left, right;
} node[1010];
int vis[1010] = {0};
vector<int> t;
void BST(int root)
{
if (node[root].left != -1)
BST(node[root].left);
t.push_back(node[root].k1);
if (node[root].right != -1)
BST(node[root].right);
}
bool isBST(int root)
{
BST(root);
for (int i = 0; i < n - 1; i++)
if (t[i] > t[i + 1])
return false;
return true;
}
bool isMinHeap(int root)
{
if (root == -1)
return true;
if (node[root].left != -1)
{
if (node[node[root].left].k2 < node[root].k2)
return false;
else if (!isMinHeap(node[root].left))
return false;
}
if (node[root].right != -1)
{
if (node[node[root].right].k2 < node[root].k2)
return false;
else if (!isMinHeap(node[root].right))
return false;
}
return true;
}
int main()
{
int root = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> node[i].k1 >> node[i].k2 >> node[i].left >> node[i].right;
if (node[i].left != -1)
vis[node[i].left] = 1;//非根节点置1
if (node[i].right != -1)
vis[node[i].right] = 1;
}
for (int i = 0; i < n; i++)
if (vis[i] == 0)
root = i;//找到根节点编号
if (isBST(root) && isMinHeap(root))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
7-3 特殊堆栈
分数 25
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
堆栈是一种经典的后进先出的线性结构,相关的操作主要有“入栈”(在堆栈顶插入一个元素)和“出栈”(将栈顶元素返回并从堆栈中删除)。本题要求你实现另一个附加的操作:“取中值”——即返回所有堆栈中元素键值的中值。给定 N 个元素,如果 N 是偶数,则中值定义为第 N/2 小元;若是奇数,则为第 (N+1)/2 小元。
输入格式:
输入的第一行是正整数 N(≤105)。随后 N 行,每行给出一句指令,为以下 3 种之一:
Push key
Pop
PeekMedian
其中 key
是不超过 105 的正整数;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
#include <bits/stdc++.h>
using namespace std;
vector<int> v1, v2;
int main()
{
vector<int>::iterator it;
int n, x, cnt;
string op;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> op;
if (op == "Push")
{
cin >> x;
v1.push_back(x);
it=lower_bound(v2.begin(),v2.end(),x);
v2.insert(it,x);
}
else if (op == "Pop")
{
if (v1.empty())
cout << "Invalid" << endl;
else
{
cout << v1.back() << endl;
it = lower_bound(v2.begin(), v2.end(), v1.back());
v2.erase(it);
v1.pop_back();
}
}
else if (op == "PeekMedian")
{
if (v1.empty())
cout << "Invalid" << endl;
else
{
cnt = (int)v2.size();
if (cnt % 2 == 1)
x = (cnt + 1) / 2 - 1;
else
x = cnt / 2 - 1;
cout << v2[x] << endl;
}
}
}
}
7-4 修理牧场
分数 25
全屏浏览题目
切换布局
作者 DS课程组
单位 浙江大学
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li的总和。
但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。
请编写程序帮助农夫计算将木头锯成N块的最少花费。
输入格式:
输入首先给出正整数N(≤104),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。
输出格式:
输出一个整数,即将木头锯成N块的最少花费。
输入样例:
8
4 5 1 2 1 3 1 1
输出样例:
49
#include <bits/stdc++.h>
using namespace std;
#define maxn 10005
priority_queue<int, vector<int>, greater<int>> p;
//优先队列默认是大顶堆(less)
//sort默认是小顶堆(less)
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int num;
cin >> num;
p.push(num);
}
long long ans = 0;
while (!p.empty())
{
int a = p.top();
p.pop();
if (p.empty())
break;
int b = p.top();
p.pop();
int c = a + b;
ans += c;
p.push(c);
}
cout << ans;
return 0;
}