一本通贪心集

最优转载问题

部分背包问题

乘船问题

选择不相交区间问题

区间选点问题

流水作业问题

1425:【例题4】加工生产调度

时间限制: 1000 ms         内存限制: 65536 KB提交数: 564     通过数: 130 

 

【题目描述】

 

某工厂收到了 nn 个产品的订单,这 nn 个产品分别在 A、B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工。

 

某个产品 ii 在 A,B 两车间加工的时间分别为Ai,BiAi,Bi。怎样安排这 nn 个产品的加工顺序,才能使总的加工时间最短。

 

这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A,B 两车间加工完毕的时间。

 

【输入】

 

第一行仅—个数据 nn ,表示产品的数量;

 

接下来 nn 个数据是表示这 nn 个产品在 A 车间加工各自所要的时间;

 

最后的 nn 个数据是表示这 nn 个产品在 B 车间加工各自所要的时间。

 

【输出】

 

第一行一个数据,表示最少的加工时间;

 

第二行是一种最小加工时间的加工顺序。

 

【输入样例】

 

5
3 5 8 7 10
6 2 1 4 9

 

【输出样例】

 

34
1 5 4 2 3

 

【提示】

 

对于100%的数据, 0 < n < 10000,所有数值皆为整数。

【题解】 

贪心; 
因为B机器在工作的时候,A机器还能够工作; 
所以就这样; 
对于A机器; 
先找一个在A机器上加工时间短的产品; 
让它在机器上加工完 
尽早让B机器开始工作; 
这样B机器和A机器它们的空闲时间就会最短了; 
同时让B机器优先加工的产品时间尽量长一点; 
这样同时在A机器上加工的产品就会尽可能地多; 
总之就是让A机器和B机器的空闲时间尽可能地短;

/*
    先找一个在A机器上加工时间短的产品;
    同时让B机器优先加工的产品时间尽量长一点;
*/


上面这两句话就是关键了; 
按照这个原则; 
处理出m[i]=min(a[i],b[i]); 
然后把m数组升序排; 
然后顺序处理n个m[i]; 
如果m是由a数组搞来的,就放在数据的最前(如果前面有元素了就尽可能靠前,否则放在序列的最后(如果最后也有元素了就尽量靠后); 
如样例,N=5 
(A1,A2,A3,A4,A5)=(3,5,8,7,10) 
(B1,B2,B3,B4,B5)=(6,2,1,4,9) 
则(m1,m2,m3,m4,m5)=(3,2,1,4,9) 
排序之后为(m3,m2,m1,m4,m5) 
处理m3:因为m3=B3,所以m3排在后面;加入m3之后的加工顺序为( , , , ,3); 
处理m2:因为m2=B2,所以m2排在后面;加入m2之后的加工顺序为( , , ,2,3); 
处理m1:因为m2=A1,所以m1排在前面;加入m1之后的加工顺序为(1, , ,2,3); 
处理m4:因为m4=B4,所以m4排在后面;加入m4之后的加工顺序为(1, ,4,2,3); 
处理m5:因为m5=B5,所以m5排在后面;加入m5之后的加工顺序为(1,5,4,2,3); 
则最优加工顺序就是(1,5,4,2,3),最短时间34。显然这是最优解。 
然后根据序列模拟出总的时间就好; 
(B机器在工作的时候,A机器也可以继续加工其他产品哦); 

 

//2018-08-03 20:09:13
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 10001;

int ans[N], a[N], b[N], m[N], s[N];
int n;

int main(){
    scanf("%d", &n);
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    for(int i=1; i<=n; i++) scanf("%d", &b[i]);
    //**********
    for(int i=1; i<=n; i++){
        m[i] = min(a[i], b[i]);
        s[i] = i;
    }
    for(int i=1;i<=n-1; i++)
        for(int j=i+1; j<=n; j++)
            if(m[i] > m[j]){
                swap(m[i], m[j]); swap(s[i], s[j]);
            }    
    int k=0, t=n+1;
    for(int i=1; i<=n; i++)
        if(m[i] == a[s[i]]){
            k++; ans[k] = s[i];
        }else{
            t--; ans[t] = s[i];
        }
    k = 0, t = 0;
    for(int i=1; i<=n; i++){
        k += a[ans[i]];
        if(t < k) t = k;
        t += b[ans[i]];
    }
    printf("%d\n", t);
    for(int i=1; i<=n; i++) printf("%d ", ans[i]);
    printf("\n");

    return 0;
}

 

 

 

带期限和罚款的单位时间任务调度

1426:【例题5】智力大冲浪时间限制: 1000 ms   

      内存限制: 65536 KB提交数: 269     通过数: 199 

 

【题目描述】

 

小伟报名参加中央电视台的智力大冲浪节目。本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元。

先不要太高兴!因为这些钱还不一定都是你的。接下来主持人宣布了比赛规则: 首先,比赛时间分为n个时段(n≤500),

它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n)。如果一个游戏没能在规定期限前完成,

则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,

保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。

作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱! 注意:比赛绝对不会让参赛者赔钱!

 

【输入】

 

输入共4行。

 

第一行为m,表示一开始奖励给每位参赛者的钱;

 

第二行为n,表示有n个小游戏; 第三行有n个数,分别表示游戏1~n的规定完成期限;

 

第四行有n个数,分别表示游戏1~n不能在规定期限前完成的扣款数。

 

【输出】

 

仅1行。表示小伟能赢取最多的钱。

 

【输入样例】

 

10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10

 

【输出样例】

 

9950

 

【提示】

 

数据范围及提示:

 

n≤500,1≤ti≤n

思路:

按罚款由大到小排序;

然后从头开始吧任务安排在不超过期限且最接近期限的位置

 

#include<iostream>
#include<algorithm>
using namespace std;
struct pp{
    int w,t;
};
pp p[505];
int vis[1000];
bool cmp(pp p1,pp p2){
    if(p1.w!=p2.w)
    return p1.w>p2.w;
    else
    return p1.t>p2.t;
}
int main(){
    int sum,n,tt,ww;
    cin>>sum>>n;
    for(int i=1;i<=n;i++) cin>>p[i].t;
    for(int i=1;i<=n;i++) cin>>p[i].w;
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++){
        int j=p[i].t;
        while(vis[j]!=0){
            j--;
            if(j==0) break;
        }
        if(j==0){
            sum-=p[i].w;
            continue;
        }
        vis[j]=1;
    }
    cout<<sum<<endl;
    return 0;
} 

 

转载于:https://www.cnblogs.com/yfr2zaz/p/10625267.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值