la 4254 Precessor

题目链接:点击打开链接

题目大意:有n个任务,每个任务有3个参数,r d w,表示要在时刻r和d之内执行完毕,工作量为w。当执行速度为s时,工作量为w的任务需要w/s个单位时间。任务可以分块执行。你需要求出处理器执行过程中最大速度的最小值,保证每个任务都能在规定时间段内完成。

思路:二分法 贪心

分析:

1. 这种类型的题应该用二分答案来做

2. 对于每次二分得到的结果应该做个判断看合不合适。办法就是定一个优先队列,每过一段时间新到达的任务以结束时间为优先级加入队列,结束时间靠前的排前面。最后看这个队列中的任务能不能在规定时间段内完成(移出队列)

3. 思路过于冗余了,其实还有更巧妙的方法。速度为s表示一个单位时间内可以完成s个工作量,从这个角度考虑,代码会更简洁清晰。毕竟还是图样。

代码:

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXS = 10000000;
const int maxn = 10000 + 10;

int n;
double last_finish;

struct task
{
	double r, d, w;
	bool operator < (const task& t) const
	{
		return d > t.d;
	}
};

task t_array[maxn];

bool comp(const task& t1, const task& t2)
{
	return t1.r < t2.r;
}

bool ok(int s)
{
	priority_queue<task> arrive_list; // 存放某时刻为止到达的所有任务,结束时间靠前的排前面
	double now_time = t_array[0].r, next_time; // 当前时刻和下个到达时刻
	int i = 0;
	while (1)
	{
		for (; i < n && t_array[i].r <= now_time; ++i)
			arrive_list.push(t_array[i]);

		next_time = i < n ? t_array[i].r : last_finish; // 如果所有任务都已经进了队列,那么下个到达时刻为最终结束时刻

		task t = arrive_list.top();
		arrive_list.pop();
		double finish_time = now_time + t.w / s;

		// 调度失败
		if (finish_time > t.d)
			return false;

		// 在下个任务到达时没能完成当前任务
		if (finish_time > next_time) 
		{
			finish_time = next_time;
			t.w -= s * (finish_time - now_time);
			arrive_list.push(t);
		}
		now_time = finish_time;

		if (arrive_list.empty()) {
			if (i == n)
				return true;
			else 
				now_time = next_time;
		}
	}
}

void init()
{
	scanf("%d", &n);
	last_finish = 0;
	for (int i = 0; i < n; i++) 
	{
		scanf("%lf %lf %lf", &t_array[i].r, &t_array[i].d, &t_array[i].w);
		last_finish = max(last_finish, t_array[i].d);
	}
	sort(t_array, t_array+n, comp);
}

void solve()
{
	int L = 1, R = MAXS;
	while (L < R)
	{
		int M = (L + R) / 2;
		if (ok(M)) R = M; else L = M + 1;
	}
	printf("%d\n", L);
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		init();
		solve();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值