优先队列的拓扑排序算法笔试题

拼多多20届学霸批算法笔试题第三题

一共有N个执行的任务,每个任务需要Pi的时间完成执行。同时,任务之间可能会有一些依赖关系。比如任务1可能依赖任务2和任务3,那么任务1必须在任务2和任务3都执行完成后才能执行。

同时只能执行一个任务,并且在任务完成之前不能暂停切换去执行其他任务。为了提升平台用户的使用体验,希望最小化任务的平均返回时长。一个任务的返回时长定义为任务执行完成时刻减去平台接收到该任务的时刻。在零时刻,所有N个任务都已经被平台接收。

安排一下任务执行顺序,使得平均返回时长最小。

输入描述:

第一行包含2个正整数N、M,分别表示任务数量以及M个任务依赖关系。

第二行包含N个正整数,第i(1 <= i <= N)个数表示第i个任务的处理时间Pi。

接下来的M行,每行表示一个任务依赖关系。每行包含2个整数Ai(1 <= Ai <= N)、Bi(1 <= Bi <= N)。表示第Bi个任务依赖于第Ai个任务。数据保证不会出现循环依赖的情况。

数据范围:

 1 <= N <= 1000

 1 <= M <= 50000

 1 <= Pi <= 10000

输出描述:

输出一行,包含N个整数(两两之间用一个空格符分隔),其中第i(1 <= i <= N)个整数表示多多鸡执行的第i个任务的编号。若有多种可行方案,则输出字典序最小(优先执行编号较小的任务)的方案。

示例:

输入:

5 6

1 2 1 1 1

1 2

1 3

1 4

2 5

3 5

4 5

输出:

1 3 4 2 5

思路:

如果不考虑依赖关系,为了实现最小平均返回时长,需要按照耗时越少任务越早执行的顺序执行,加上依赖关系后,我们一定要做完依赖任务才能进行依赖后的任务,只有依赖任务的数量为0(表示依赖任务做完,才能进行本任务的执行),这里的执行顺序还是按照处理时间排序;使用小顶堆存储当前可以执行的任务, 每次出堆后更新依赖次数, 依赖次数为0的任务加入到优先队列中

C++代码:

#include
#include
#include 
#include 
#include 
#include


using namespace std;

typedef struct Task{
	int seq;    //任务序列号(1,2,3,...,N)
	int time;   //任务处理时间
	Task() :seq(0), time(0){}
}Task;

struct cmp{
	bool operator()(const Task &a, const Task &b)
	{
		return a.time != b.time ? a.time > b.time : a.seq > b.seq;  //输出字典序最小(优先执行编号较小的任务)
		//return a.time > b.time;   //将time利用小顶堆排序,首先将小数输出
		//return a.time < b.time    //将time利用大顶堆排序,首先将大数输出
	}
};

int main(void){
	int N, M;
	cin >> N >> M;    //输入的任务数量N(1,2,3,...,N)和任务依赖关系数量
	
	vector task(N + 1);   //存放任务
	vector > Adj(N+1, list());  //邻接表
	vector inDegree(N+1, 0);     //保存每个节点的入度
	
	//输入任务的处理时间
	for (int i = 1; i < N + 1; ++i)
	{
		Task tmp;
		tmp.seq = i;
		cin >> tmp.time;
		task[i] = tmp;
	}
	//输入任务的依赖关系建立邻接矩阵
	for (int i = 0; i < M; ++i)
	{
		int u, v;
		cin >> u >> v;
		Adj[u].push_back(v);
		inDegree[v]++;
	}
	//将入度为0的任务放入队列
	priority_queue, cmp> taskque;
	for (int i = 1; i < N + 1; ++i)
	{
		if (inDegree[i] == 0)
			taskque.push(task[i]);
	}
	
	//进行拓扑排序
	vector tasksort;
	while (!taskque.empty())
	{
		Task complete = taskque.top();
		taskque.pop();
		list::iterator ite = Adj[complete.seq].begin();
		for (; ite != Adj[complete.seq].end(); ++ite)
		{
			inDegree[*ite]--;
			if (inDegree[*ite] == 0)
				taskque.push(task[*ite]);
		}
		tasksort.push_back(complete.seq);
	}
	//输出任务顺序
	for (auto task : tasksort)
	{
		cout << task << " ";
	}
	cout << endl;
	return 0;
}

--------------------------------------------------

参考博客:

C++ priority_queue用法(大顶堆,小顶堆)

【c++】STL里的priority_queue用法总结

拼多多2019学霸批笔试

你可能感兴趣的:(Algorithm_note)