算法作业-批处理作业调度-回溯|分支限界法

问题描述
给定 n 个作业的集合 j = {j1, j2, …, jn}。每一个作业 j[i] 都有两项任务分别在两台机器上完成。每一个作业必须先由机器1 处理,然后由机器2处理。作业 j[i] 需要机器 j 的处理时间为 t[j][i] ,其中i = 1, 2, …, n, j = 1, 2。对于一个确定的作业 调度,设F[j][i]是作业 i 在机器 j 上的完成处理的时间。所有作 业在机器2上完成处理的时间之和 f = sigma F[2][i] 称为该作业 调度的完成时间之和。
批处理作业调度问题要求对于给定的 n 个作业,制定最佳作业调度 方案,使其完成时间和达到最小。

tji 机器1 机器2
作业1 2 1
作业2 3 1
作业3 2 3
这3个作业的6种可能的调度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;
它们所相应的完成时间和分别是19,18,20,21,19,19。易见,最佳调度方案是1,3,2,其完成时间和为18。
以1,2,3为例:
作业1在机器1上完成的时间为2,在机器2上完成的时间为3
作业2在机器1上完成的时间为5,在机器2上完成的时间为6
作业3在机器1上完成的时间为7,在机器2上完成的时间为10
3+6+10=19,所以是19

1,3,2
作业1在机器1上完成的时间为2, 在机器2上完成的时间为3
作业3在机器1上完成的时间为4,在机器2上完成的时间为7
作业2在机器1上完成的时间为7,在机器2上完成的时间为8
3+7+8=18,所以时间和为18

思路:1 就是用回溯算出所有的状态。当然可以剪一下值,就是当前算出来的值大于目标时,就不用再继续了。我是直接枚举全排列算的。排列树?? qwq 不太清楚。
第二个用的广搜写的。其实用队列也行,用优先队列没有啥必要。。
只是为了熟悉一下。
还有一个地方,那就是这个如果要加状态的时候,还要学习第一个加一个vector,我没有加。

#include <bits/stdc++.h>
using namespace std;
/* 用优先队列搞一下。但是这样写状态有点多。。
   用位运算写,比较方便。但是只能表示64个机器。注意!
   分支限界qwq
*/
typedef long long ll;
const int maxn=1e5;
struct ED{
    ll cos1;
    ll cos2;
}node[maxn];
struct Node{
    ll clo;
   ll status;
    int siz;
    ll all;
    ll qzh;//没错,就是前缀和。。
    Node(ll _clo,ll  _status,int _siz,ll _all,ll _qzh){
       clo=_clo;
       status=_status;
       siz=_siz;
       all=_all;
       qzh=_qzh;
    }
   friend bool operator<(Node a,Node b){
        return a.siz>b.siz;
   }
};
priority_queue<Node>q;
int main()
{   int t;
    ll  sta;
    while(cin>>t){
          for(int i=0;i<t;i++){
              cin>>node[i].cos1>>node[i].cos2;
              sta=0;
              sta|=(1<<i);
              q.push(Node(node[i].cos2+node[i].cos1,sta,1,node[i].cos2+node[i].cos1,node[i].cos1));
          }
          ll ans=1e17;
          while(!q.empty()){
               Node u=q.top();
               q.pop();
               if(u.all>ans) continue;//剪枝。
               if(u.siz==t){
                  /*for(int i=0;i<t;i++){
                      if((u.status&(1<<1)))
                         cout<<i<<"**";
                  }
                  cout<<endl;*/
                  ans=min(ans,u.all);
                  continue;
               }
               for(int i=0;i<t;i++){
                   if((u.status&(1<<i))==0){
                       ll cloo=max(u.qzh+node[i].cos1,u.clo)+node[i].cos2;
                      ll all1=u.all+cloo;
                      q.push(Node(cloo,u.status|(1<<i),u.siz+1,all1,u.qzh+node[i].cos1));
                   }
               }
          }
          printf("%lld\n",ans);
    }
    return 0;
} 
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
/* 批处理作业调度。
    记录一个结尾时间。
    这样写不方便剪枝。可以把vector传参传过去。
    dfs。
*/
const int maxn=1e5;
ll ans;
ll  sum[maxn];
bool vis[maxn];
vector<int>v;
vector<int>vv;
int m;
struct Node{
      int sec1;
      int sec2;
}node[maxn];
int siz;
void dfs(int x){
    if(siz==m){
        ll tim=0;
        ll all=0;
        sum[0]=node[v[0]].sec1;
        for(int i=1;i<v.size();i++){
            sum[i]=sum[i-1]+node[v[i]].sec1;
        }
        for(int i=0;i<v.size();i++){
            all+=max(sum[i],tim)+node[v[i]].sec2;
            tim=max(sum[i],tim)+node[v[i]].sec2;
        }
        cout<<all<<endl;
        if(ans>all){
            vv.clear();
            for(int i=0;i<v.size();i++)
                vv.push_back(v[i]);
                ans=all;
        }
        return ;
    }
    for(int i=1;i<=m;i++){
         if(!vis[i]){
         vis[i]=true;
         v.push_back(i);
         siz++;
         dfs(i);
         siz--;
         vis[i]=false;
         v.pop_back();
         }
    }
    return ;
}
int main()
{
     while(cin>>m){
           if(!m) break;
           v.clear();
           vv.clear();
           memset(vis,false,sizeof(vis));
           siz=0;
           ans=1e17+7;
           for(int i=1;i<=m;i++){
               cin>>node[i].sec1>>node[i].sec2;
           }
           dfs(0);
           printf("最后的结果qwq\n");
           for(int i=0;i<vv.size();i++){
               if(i==0)
                 printf("%d",vv[i]);
               else
                  printf(" %d",vv[i]);
           }
           puts("");
           printf("%lld\n",ans);
     }
    return 0;
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分支限界法(Branch and Bound)是一种用于求解离散优化问题的算法,它在整数规划和搜索问题中特别有效,包括某些类型的作业调度问题。在作业调度中,假设每个作业有一个开始时间和结束时间,目标可能是找到一种最优的作业安排,使得完成所有作业的时间最短或者满足特定的资源约束。 对于批处理作业调度问题,其中涉及到多个任务作业每个任务有一个执行时间和优先级。分支限界法可以应用于以下场景: 1. **任务排序**:决定哪些任务应该首先执行,然后根据剩余的任务调整策略,比如采用最早开始时间(EDF, Earliest Deadline First)或最迟结束时间(LDF, Latest Finish Time)策略。 2. **资源分配**:如果有共享资源,如何分配这些资源以最大化效率或最小化截止日期违反。 3. **动态规划**:通过构建决策树,将问题分解为子问题,并利用上一阶段的结果来指导当前阶段的选择。 分支限界法的工作流程大致如下: - **节点生成**:从初始状态开始,生成所有可能的子状态(即可能的作业执行顺序)。 - **剪枝**:评估每个节点的上界(upper bound)或下界(lower bound),如果当前节点的目标值肯定超过最优解,就直接舍弃。 - **分支**:选择具有最大潜力提升的子节点进行深入。 - **回溯**:当达到某个节点没有更好的解决方案时,回溯到父节点并尝试其他分支。 - **递归终止条件**:当找到满足目标条件的解或者搜索树被完全探索后,算法停止。 **相关问题--:** 1. 作业调度问题中的具体优化目标是什么? 2. 在批处理作业调度中,如何定义节点的剪枝条件? 3. 分支限界法如何处理优先级变化或资源限制对任务顺序的影响?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值