回溯法(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; } |
参考资料 《算法设计与分析》王晓东编著
授课教师 张阳教授
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 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——大语言模型本地部署的极速利器