【bzoj2336】[HNOI2011]任务调度

题目链接

Description

有 N 个任务和两台机器 A 与 B。每个任务都需要既在机器 A 上执行,又在机器 B 上执行,第 i 个任务需要在机器 A 上执行时间 Ai,且需要在机器 B 上执行时间 Bi。最终的目标是所有任务在 A 和 B 上都执行完,且希望执行完所有任务的总时间尽量少。当然问题没有这么简单,有些任务对于先在机器 A 上执行还是先在机器 B 上执行有一定的限制。据此可将所有任务分为三类:
1.任务必须先在机器 A 上执行完然后再在机器 B 上执行。
2.任务必须先在机器 B 上执行完然后再在机器 A 上执行。
3.任务没有限制,既可先在机器 A 上执行,也可先在机器 B 上执行。
现在给定每个任务的类别和需要在机器A和机器B上分别执行的时间,问使所有任务都能按规定完成所需要的最少总时间是多少。

Input

从文件input.txt中读入数据,输入文件的第一行只有一个正整数N(1≤N≤20),表示任务的个数。接下来的N行,每行是用空格隔开的三个正整数Ti, Ai, Bi(1≤Ti≤3, 1≤Ai, Bi≤1000),分别表示第i个任务的类别(类别1, 2, 3的定义如上)以及第i个任务需要在机器A和机器B上分别执行的时间。

Output

输出文件 output.txt 仅包含一个正整数,表示所有任务都执行完所需要的最少总时

Sample Input

3
3 5 7
1 6 1
2 2 6
14

Sample Output

14

Hint

样例解释:一种最优任务调度方案为:机器A上执行的各任务依次安排如下:任务1(0 - 5), 任务2(5 - 11), 任务3(11 - 13);机器B上执行的各任务依次安排如下:任务3(0 - 6), 任务 1(6 - 13), 任务2(13 - 14),这样,所有任务都执行完所需要的总时间为14。

题解

乖乖,随机化。
惊了,还以为是DP。
枚举每个3类型到底是1类型还是2类型,然后所有1类型按b时间从大到小排序,所有2类型按a时间从大到小排序,先贪心一下现在的答案。再随机交换一下做任务的顺序,如果更优就更换,如果不优就不换,就这样。

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

const int N = 30, inf = 0x3f3f3f3f;

int n, a[N], b[N], t[N];
int stk1[N], top1, stk2[N], top2;
bool wh[N];
int ans = inf;

bool cmp1(int p, int q){
    if(b[p] == b[q]) return a[p] < a[q];
    return b[p] > b[q];
}

bool cmp2(int p, int q){
    if(a[p] == b[q]) return b[p] < b[q];
    return a[p] > a[q];
}

void init(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d%d%d", &t[i], &a[i], &b[i]);
}

int calc(){
    int sa = 0, sb = 0, ret = 0;
    for(int i = 1; i <= top2; i++) sb += b[stk2[i]];
    for(int i = 1; i <= top1; i++){
        sa += a[stk1[i]];
        if(sa < sb) sb += b[stk1[i]];
        else sb = sa + b[stk1[i]];
    }
    ret = max(sa, sb);
    sa = sb = 0;
    for(int i = 1; i <= top1; i++) sa += a[stk1[i]];
    for(int i = 1; i <= top2; i++){
        sb += b[stk2[i]];
        if(sb < sa) sa += a[stk2[i]];
        else sa = sb + a[stk2[i]];
    }
    return max(ret, max(sa, sb));
}

void solve(){
    top1 = top2 = 0;
    for(int i = 1; i <= n; i++)
        if(wh[i]) stk2[++top2] = i; else stk1[++top1] = i;
    sort(stk1+1, stk1+top1+1, cmp1);
    sort(stk2+1, stk2+top2+1, cmp2);
    int ret = calc(), t = 2000, a1, a2, b1, b2, tmp;
    while(t--){
        if(top1)
            swap(stk1[a1 = rand()%top1+1], stk1[a2 = rand()%top1+1]);
        if(top2)
            swap(stk2[b1 = rand()%top2+1], stk2[b2 = rand()%top2+1]);
        tmp = calc();
        if(tmp < ret) ret = tmp;
        else{
            if(top1) swap(stk1[a1], stk1[a2]);
            if(top2) swap(stk2[b1], stk2[b2]);
        }
    }
    if(ret < ans) ans = ret;
}

void dfs(int k){
    if(k > n) solve();
    else
        switch(t[k]){
            case 1: wh[k] = 0; dfs(k + 1); break;
            case 2: wh[k] = 1; dfs(k + 1); break;
            case 3: wh[k] = 0; dfs(k + 1); wh[k] = 1; dfs(k + 1); break;
        }
}

void work(){
    dfs(1);
    printf("%d\n", ans);
}

int main(){
    srand(10100619);
    init();
    work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值