回溯法(2)

二、批处理作业调度

问题表述给定n个作业的集合{J1,J2,…,Jn}。每个作业必须先由机器1处理,然后由机器2处理。作业Ji需要机器j的处理时间为tji。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

批处理作业调度问题要求对于给定的n个作业,制定最佳作业调度方案,使其完成时间和达到最小。

显然,1,3,2是最佳调度方案。

解空间:排列树(将作业顺序进行全排列,分别算出各种情况的完成时间和,取最佳调度方案

实现:

/* 主题:批处理作业调度算法
* 作者:chinazhangjie
* 邮箱:chinajiezhang@gmail.com
* 开发语言:C++
* 开发环境:Mircosoft Virsual Studio 2008
* 时间: 2010.10.24
*/
 
#include <iostream>
#include <vector>
using namespace std;
 
class flowshop
{
public:
    flowshop(vector<vector<int> >& rhs) {
        task_count = rhs.size() ;
        each_t = rhs ;
        best_t.resize (task_count) ;
        machine2_t.resize (task_count,0) ;
        machine1_t = 0 ;
        total_t = 0 ;
        best_total_t = 0 ;
 
        current_t.resize (task_count,0) ;
        for (int i = 0 ;i < task_count; ++ i) {
            current_t[i] = i; // 为了实现全排列
        }
    }
    void backtrack () {
        __backtrack (0);
        // 显示最佳调度方案和最优完成时间和
        cout << "the best flowshop scheme is : ";
        copy (best_t.begin(),best_t.end(),ostream_iterator<int> (cout, " "));
        cout << endl;
        cout << "the best total time is : " << best_total_t << endl;
    }
 
private:
    void __backtrack (int i) {
        if (i >= task_count) {
            if (total_t < best_total_t || best_total_t == 0) {
                // 存储当前最优调度方式
                copy (current_t.begin(),current_t.end(),best_t.begin()) ;
                best_total_t = total_t;
            }
            return ;
        }
        for (int j = i; j < task_count; ++ j) {
            // 机器1上结束的时间
            machine1_t += each_t[current_t[j]][0] ;
            if (i == 0) {
                machine2_t[i] = machine1_t + each_t[current_t[j]][1] ;
            }
            else {
                // 机器2上结束的时间
                machine2_t[i] =
                    ((machine2_t[i - 1] > machine1_t) ? machine2_t[i - 1] : machine1_t)
                     + each_t[current_t[j]][1] ;
            }
 
            total_t += machine2_t[i];
            // 剪枝
            if (total_t < best_total_t || best_total_t == 0) {
                // 全排列
                swap (current_t[i],current_t[j]) ;
                __backtrack (i + 1) ;
                swap (current_t[i],current_t[j]) ;
            }
 
            machine1_t -= each_t[current_t[j]][0] ;
            total_t -= machine2_t[i] ;
        }
    }
 
public :
    int task_count ;        // 作业数
    vector<vector<int> >  each_t ;  // 各作业所需的处理时间
    vector<int>   current_t ; // 当前作业调度
    vector<int> best_t ;      // 当前最优时间调度
    vector<int> machine2_t ;  // 机器2完成处理的时间
    int machine1_t ;        // 机器1完成处理的时间
    int total_t ;           // 完成时间和
    int best_total_t ;      // 当前最优完成时间和
};
 
int main()
{
    // const int task_count = 4;
    const int task_count = 3 ;
    vector<vector<int> > each_t(task_count) ;
    for (int i = 0;i < task_count; ++ i) {
        each_t[i].resize (2) ;
    }
    each_t[0][0] = 2 ;
    each_t[0][1] = 1 ;
    each_t[1][0] = 3 ;
    each_t[1][1] = 1 ;
    each_t[2][0] = 2 ;
    each_t[2][1] = 3 ;
    // each_t[3][0] = 1 ;
    // each_t[3][1] = 1 ;
 
    flowshop fs(each_t) ;
    fs.backtrack () ;
}

三、n后问题 

问题表述:在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。求不同的解的个数。

 

解向量:(x1, x2, … , xn)

显约束:xi = 1,2, … ,n

隐约束:

    1)不同列:xi != xj

    2)不处于同一正、反对角线:|i-j| != |x(i)-x(j)|

解空间:满N叉树

实现:

/* 主题:n后问题
* 作者:chinazhangjie
* 邮箱:chinajiezhang@gmail.com
* 开发语言:C++
* 开发环境:Mircosoft Virsual Studio 2008
* 时间: 2010.10.24
*/
 
#include <iostream>
#include <vector>
using namespace std;
 
class queen
{
    // 皇后在棋盘上的位置
    struct q_place {
        int x;
        int y;
        q_place ()
            : x(0),y(0)
        {}
    };
 
public:
    queen(int qc)
    : q_count (qc), sum_solution (0) {
        curr_solution.resize (q_count);
    }
 
    void backtrack () {
        __backtrack (0);
    }
 
private:
    void __backtrack (int t) {
        if (t >= q_count) {
            // 找到一个解决方案
            ++ sum_solution ;
            for (size_t i = 0;i < curr_solution.size(); ++ i) {
                cout << "x = " << curr_solution[i].x
                    << " y = " << curr_solution[i].y << endl;
            }
            cout << "sum_solution = " << sum_solution << endl;
        }
        else {
            for (int i = 0;i < q_count; ++ i) {
                curr_solution[t].x = i;
                curr_solution[t].y = t;
                if (__place(t)) {
                    __backtrack (t + 1);
                }
            }
        }
    }
    // 判断第k个皇后的位置是否与前面的皇后相冲突
    bool __place (int k) {
        for (int i = 0; i < k; ++ i) {
            if ((abs(curr_solution[i].x - curr_solution[k].x)
                == abs(curr_solution[i].y - curr_solution[k].y))
                || curr_solution[i].x == curr_solution[k].x) {
                return false;
            }
        }
        return true;
    }
 
private:
    vector<q_place> curr_solution;    // 当前解决方案
    const int q_count;              // 皇后个数
    int sum_solution;               // 当前找到的解决方案的个数
};
 
int main()
{
    queen q(5);
    q.backtrack ();
    return 0;
}

 

参考资料  《算法设计与分析》王晓东编著

授课教师 张阳教授

 

posted @   独酌逸醉  阅读(2519)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
点击右上角即可分享
微信分享提示