【编程题】产品经理

产品经理(PM)有很多好的idea,而这些idea需要程序员实现。现在有N个PM,在某个时间会想出一个 idea,每个 idea 有提出时间、所需时间和优先等级。对于一个PM来说,最想实现的idea首先考虑优先等级高的(优先度数字越小越高),相同的情况下优先所需时间最小的,还相同的情况下选择最早想出的,没有 PM 会在同一时刻提出两个 idea。

同时有M个程序员,每个程序员空闲的时候就会查看每个PM尚未执行并且最想完成的一个idea,然后从中挑选出所需时间最小的一个idea独立实现,如果所需时间相同则选择PM序号最小的。直到完成了idea才会重复上述操作。如果有多个同时处于空闲状态的程序员,那么他们会依次进行查看idea的操作。

求每个idea实现的时间。

输入第一行三个数N、M、P,分别表示有N个PM,M个程序员,P个idea。随后有P行,每行有4个数字,分别是PM序号、提出时间、优先等级和所需时间。输出P行,分别表示每个idea实现的时间点。

输入描述:

输入第一行三个数N、M、P,分别表示有N个PM,M个程序员,P个idea。
随后有P行,每行有4个数字,分别是PM序号、提出时间、优先等级和所需时间。
全部数据范围 [1, 3000]

输出描述:

输出P行,分别表示每个idea实现的时间点。

示例:

输入例子1:
2 2 5
1 1 1 2
1 2 1 1
1 3 2 2
2 1 1 2
2 3 5 5

输出例子1:
3
4
5
3
9

解析:
这到题要考虑的陷阱有点多:
1、这里存在两次显示的排序,一个是pm对自身的想法的排序,一个是程序员对pm们给的idea的一个排序(如程序员不会考虑idea的优先等级等,“最想要”应该是已经被pm提前抽象化了。),不能两者同时排序

2、当前程序员有空但新的idea还没有提出来。因此程序员应当对当前已经提出的idea排序

示例解析:
idea的提出时间表:
在这里插入图片描述
在时间点1,pm们提出了idea1,和idea4
此时两个程序员刚好完成,因此idea1和idea4的完成时间都是1+2=3

在时间点2,pm1提出idea2
但由于两个程序员在忙着idea1和idea4,所以占时被搁置,此时pm1的优先队列有一个元素

在时间点3,pm们提出idea3和idea5
此时,pm1的优先队列有2个元素,按照排序,先按优先等级大的排序,idea3是他目前最想做的,因此被加入到程序员的队列中,而pm2只有一个元素,因此直接加入

然后,程序员开始对队列排序,程序员1选择了耗费时间少的idea3,因此idea3的完成时间是3+2=5

此时,程序员2再次对队列排序,他挑选每个PM尚未执行并且最想完成的一个idea,即pm1的idea2被加入到程序员的队列中,显然,idea2耗费时间比idea5的要少,因此程序员2选择了idea2,因此idea2的完成时间为3+1=4

在时间点4
此时程序员2刚做完idea2,因此他被塞了idea5,因此idea5的完成时间为4+5=9
代码:

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

struct Idea
{
	int id;     //序号,用于输出问题
	int pm;     //pm序号
	int time;   //提出时间
	int level;  //优先等级
	int useTime;//花费时间

	Idea(int id, int pm, int time, int level, int useTime) :
		id(id), pm(pm), time(time), level(level), useTime(useTime) {}
};

//仿函数
//pm对idea的排序
//注意,在使用优先队列时,优先队列使用的是堆排序,这使第三参数的效果与sort相反
struct cmp_pm
{
	bool operator()(const Idea& a,const Idea& b)
	{
		//先按优先等级降序
		if(a.level!=b.level)
		{
			return a.level < b.level;
		}
		//再按所需时间升序
		else if(a.useTime!=b.useTime)
		{
			return a.useTime > b.useTime;
		}
		//再按提出时间升序
		else
		{
			return a.time > b.time;
		}
	}
};

//程序员对idea的排序
struct cmp_pro
{
	bool operator()(const Idea&a,const Idea&b)
	{
		//先按所需时间最少的升序
		if(a.useTime!=b.useTime)
		{
			return a.useTime > b.useTime;
		}
		//再按pm号升序
		else
		{
			return a.pm > b.pm;
		}
	}
};

//按时间排序,用于判断当前时间点
bool cmp_time(const Idea&a,const Idea&b)
{
	return a.time < b.time;
};

int main()
{
	int N, M, P;//pm,程序员,idea
	cin >> N >> M >> P;

	//读入idea数组
	vector<Idea> ideas;
	int pm, time, level, useTime;
	for(int i=0;i<P;i++)
	{
		cin >> pm >> time >> level >> useTime;
		ideas.emplace_back(Idea(i, pm - 1, time, level, useTime));
	}

	//记录idea结束时间
	vector<int> ans(P);
	//记录程序员剩余工作时间,只有在对应剩余时间为0才能添加新的idea任务
	vector<int> pro(M, 0);

	//N个优先队列,用于存储 当前时间点前所有未执行的idea ,并对他们排序
	priority_queue<Idea, vector<Idea>, cmp_pm> cur_ideas[2005];

	//先按提出时间排序,将提出的idea逐个加入程序员的排序中
	sort(ideas.begin(), ideas.end(), cmp_time);

	int count = 0;//idea已完成数
	int p = 0;    //idea编号
	time = 1;     //当前时间点
	while (count<P)
	{
		//当队列中的idea的提出时间小于等于当前时间,则可加入到 每个pm当前最想做的idea的排序中
		while (p<P&&ideas[p].time<=time)
		{
			cur_ideas[ideas[p].pm].push(ideas[p]);
			p++;
		}

		//将每个pm当前最想做的idea加入到程序员的工作队列中,让程序员排序选择
		//程序员的工作队列
		priority_queue<Idea, vector<Idea>, cmp_pro> q;
		for(int i=0;i<N;i++)
		{
			//注意判断当前pm队列是否为空
			if(!cur_ideas[i].empty())
			{
				//由于当前的idea不一定被做,所以不着急先pop
				q.push((cur_ideas[i].top()));
			}
		}

		//更新程序员工作时间表
		for(int i=0;i<M;i++)
		{
			//时间-1
			if(pro[i]>0)
			{
				pro[i]--;
			}
			//如果当前程序员空闲,即时间为0,在idea队列不为空的情况下加入新的工作
			if(pro[i]==0&&!q.empty())
			{
				//获取当前最优先idea并弹出
				Idea idea = q.top();
				q.pop();
				//同时需弹出对应的pm序列,以更新pm当前最想做的idea
				cur_ideas[idea.pm].pop();

				//当当前idea被执行后,需加入它对应pm的次优先idea加入队列中,
				//因为这个次优先的idea可能比其他idea优先 等级要高
				//保证程序员队列中任何pm的idea都有
				if(!cur_ideas[idea.pm].empty())
				{
					q.push(cur_ideas[idea.pm].top());
				}

				//更新程序员的工作时间表
				pro[i] = idea.useTime;
				//记录这个idea的完成时间
				ans[idea.id] = time + idea.useTime;
				//更新事件完成数量
				count++;
			}
		}

		//完成一批idea后记得更新时间
		time++;
	}

	//最后按结束时间输出即可
	for(int i=0;i<P;i++)
	{
		cout << ans[i] << endl;
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值