【ETOJ P1036】我踏马吃吃吃吃吃 题解(优先队列+贪心算法)

题目描述

有n个人在m个窗口打饭,因为每个人的需求不同,所以每个人的“窗口占用时间”也不同。第i个人的窗口占用时间为 t i t_i ti

请问如何安排这些人到窗口打饭,可以使得所有人等待的时间之和最小?

输入格式

第一行两个整数n,m。 ( 1 ≤ n ≤ 2 × 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 ) (1 \leq n \leq 2 \times 10^5, 1 \leq m \leq 2 \times 10^5) (1n2×105,1m2×105)

接下来一行,n个整数表示 t i t_i ti ( 1 ≤ t i ≤ 1 0 9 ) (1 \leq t_i \leq 10^9) (1ti109)

输出格式

一个整数表示答案。

样例

输入1

5 3
3 2 1 5 7

输出1

3

解释: ( 1 , 5 ) , ( 2 , 7 ) , ( 3 ) (1,5),(2,7),(3) (1,5),(2,7),(3),这样安排可以使得每个人的等待时间之和最小,为3。


思路

这是一个最小延迟调度问题。目标是找到一种方法,将n个人分配到m个窗口,使得所有人的等待时间之和最小。每个人的窗口占用时间已知。

使用两个优先队列,pq1和pq2。pq1用于存储所有人的窗口占用时间,pq2用于存储每个窗口的总等待时间。首先,所有人的窗口占用时间被读入pq1,m个窗口的初始等待时间(都为0)被读入pq2。

在每一步,都选择将当前等待时间最短的窗口分配给下一个人。进入一个循环,直到所有人都被分配到窗口为止。在每一步,从pq1中取出一个人,从pq2中取出当前等待时间最短的窗口,将这个人分配到这个窗口上,然后更新这个窗口的总等待时间,并将其重新插入pq2。同时,这个窗口的等待时间被加入到总等待时间ans中。

当所有人都被分配到窗口后,总等待时间ans就是要求的答案。这个答案代表了所有人的等待时间之和的最小值。


AC代码

#include 
#include 
#include 
#define AUTHOR "HEX9CF"
#define ll long long
using namespace std;

int n, m;
ll ans;
priority_queue<int, vector<int>, greater<int>> pq1, pq2;

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		int t;
		cin >> t;
		pq1.push(t);
	}
	for (int i = 1; i <= m; i++) {
		pq2.push(0);
	}
	ans = 0;
	while (pq1.size()) {
		// cout << pq1.top() << " " << pq2.top() << endl;
		ans += pq2.top();
		pq2.push(pq2.top() + pq1.top());
		pq1.pop();
		pq2.pop();
	}
	cout << ans << endl;
	return 0;
}

【ETOJ P1036】我踏马吃吃吃吃吃 题解(优先队列+贪心算法)_第1张图片

你可能感兴趣的:(Algorithm,Problems,贪心算法,算法)