HDU 6180 Schedule(贪心 - 任务调度问题)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6180

在这里插入图片描述

任务调度问题:
  给定 n 个任务,每个任务的开始时间为 si,结束时间为 ei (1 ≤ i ≤ n, 0 ≤ si < ei),并且每个任务只能在一台机器上面完成,每台机器一次只能完成一个任务。如果任务 i 和任务 j 满足 ei < sj 或者 ej < si,则任务 i 和任务 j 是不冲突的,可以在一台机器上完成。任务调度问题就是在任务不冲突的情况下,用尽量少的机器完成 n 个任务。
任务调度问题解决方案 :

  • 首先先按照开始时间或者结束时间对区间进行排序(根据题意选择合适排序) ,然后遍历区间

  • 方案一: 如果一个任务能做,那么就让最早结束的机器去做,队列中每次弹出最早结束的的那个人去做这个任务。

#include<bits/stdc++.h>
using namespace std;

const int Max_n=1e5+10;
pair<int,int>a[Max_n];

int n,m;
priority_queue<int>q;//维护最早的结束时间

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        while(!q.empty()) q.pop();
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%d%d",&a[i].first,&a[i].second);
        sort(a,a+n);//默认开始时间排序
        int sum=0;
        for(int i=0;i<n;i++){
            if(q.size()&&-q.top()<=a[i].first){//结束时间小于开始时间,每次都找结束时间最早的那个人去做
                q.pop();//弹出这个人的结束时间
                q.push(-a[i].second);
            }else{//队列中所有人都无法做此任务
                q.push(-a[i].second);//加一个人并且把它的结束时间加进去
                sum++;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}
  • 方案二:如果一个任务可以做,我们就找到他距离此任务最近(结束时间最近)的任务去做,我们用 muliset 维护一个结束之间,无疑最早的结束时间就是 *s.begin() ,如果一个任务的开始时间大于这个值说明 multiset 中有人可以做这个任务,我们用二分的方法找到大于这个开始时间的第一个结束时间,那么这个结束时间的前面一个结束时间就是距离这个任务结束时间最近的任务。让这个人去做当前的任务。
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int>P;
const int Max_n=1e5+10;
P a[Max_n];

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		multiset<int>s;//维护每个人的结束时间
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d%d",&a[i].first,&a[i].second);
		sort(a+1,a+n+1);//按照开始时间排序
		int sum=0;
		for(int i=1;i<=n;i++){
			if(s.size()&&*s.begin()<=a[i].first){//当前任务不冲突(结束时间<=开始时间)
				s.erase(--s.upper_bound(a[i].first));//删除距离此任务最近的结束时间
				s.insert(a[i].second);//更新这个人的结束时间
			}else{//冲突,直接增加一个人并且更新他的结束时间
				sum++;
				s.insert(a[i].second);
			}
		}
		printf("%d\n",sum);
	}
	return 0;
}

  题意:给你 n 个任务的开始时间和结束时间,这些任务可以由若干台机器完成,问在所有任务都不冲突的情况下,最少需要用多少台机器,并且求出所有机器的工作时间的最小总和。
  思路:对于最少的机器用上面两种方案的任何一种都行,但是此题还要保证所有机器的工作时间最小,那么我们就可以理解为某个任务的开始时间一定是距离一个任务的结束时间最近的。这样我们就将问题转化为了方案二的问题。对于一个任务,我们在找其是否冲突的时候,一定要先找到开始时间最早的那个任务去判断,所有我们的排序方式是按照开始时间排序。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int>P;
const int Max_n=1e5+10;
P a[Max_n];

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		multiset<int>s;//维护每个机器的结束时间
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d%d",&a[i].first,&a[i].second);
		sort(a+1,a+n+1);//任务按照开始时间排序
		ll ans=0;
		int sum=0;
		for(int i=1;i<=n;i++){
			if(s.size()&&*s.begin()<=a[i].first){
				int t=*(--s.upper_bound(a[i].first));//找到最近的结束时间
				ans+=a[i].second-t;//记录时间
				s.erase(--s.upper_bound(a[i].first));//删除最近的结束时间
				s.insert(a[i].second);//更新结束时间
			}else{
				sum++;
				ans+=a[i].second-a[i].first;//记录时间差
				s.insert(a[i].second);//更新新人的结束时间-
			}
		}
		printf("%d %lld\n",sum,ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值