1.问题分析
在之前的博客中https://blog.csdn.net/Jayphone17/article/details/102996649
我们用回溯法解决了机器零件加工最优加工顺序问题
我们分析一下那个情况的复杂度:
(1)时间复杂度,如图所示:
最坏情况下,除了最后一层外,有1+n+n(n-1)+…+n(n-1)(n-2)…≤ nn!个结点需要判断限界函数,判断限界函数需要O(1)的时间,因此耗时O(nn!)。在叶子结点记录最优解耗时O(n),最坏情况下会搜索每一个叶子结点,叶子个数有n!,耗时O(nn!)。最后时间复杂度是O(nn!)≈O((n+1)!)。
(2)空间复杂度。使用了x[ ]数组记录最长路径作为可行解,空间复杂度是O(n)。
使用贝尔曼规则进行优化,时间复杂度可以达到O(nlogn)。
假设在S集合中加工顺序中,最有加工方案只有以下两种方案之一:
- 先加工i号零件,再加工j号零件,其他工件加工顺序是最优
- 先加工j号零件,再加工i号零件,其他工件加工顺序是最优
根据贝尔曼的推导公式:https://blog.csdn.net/Jayphone17/article/details/103013335
方案1比方案优的充分必要条件是:max{ t1j,t2i } ≥ max{ t1i,t2j }。
继续分析之后:
由此可以得到贝尔曼规则:
- 第一台机器上加工时间越短的工件越先加工
- 第二台机器上加工时间越短的工件越后加工
- 第一台机器上加工时间小于第二台机器上加工时间的先加工
- 第一台机器上加工时间大于等于第二台机器上加工时间的后加工
2.算法设计
一、
(1)根据贝尔曼规则可以把零件分成两个集合:N1={ i | t1i < t2i } ,即第一台机器上加工的时间小于第二台机器上加工时间;
N2={ i | t1i >= t2i } ,即第一台机器上加工的时间大于等于第二台机器上加工时间
(2)将N1工件按照 t1i 非递减排序,将N2中的工件按照 t2i 非递增排序。
(3)N1中工件接N2中工件,即N1N2就是所求的满足贝尔曼规则的最优加工顺序。
二、
因为C++中可以自定义排序函数的优先级,因此先定义优先级cmp,然后调用sort函数即可。
bool cmp(node a,node b) { return min(b.x,a.y)>=min(a.x,b.y); } sort (T,T+n,cmp);
具体这个优先级是什么意思呢?
例如现在有a,b两个零件,在第一台机器加工时间是x,在第二台机器上加工时间是y。
min(b.x,a.y)=min(10,7)=7。
min(b.y,a.x)=min(2,3)=2。
min(b.x,a.y)≥ min(b.y,a.x)。// 贝尔曼规则!!!!
因此a零件加工排在b前面。
3.源代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int MX=11111; int n; struct node { int x; int y; int id; }T[MX]; bool cmp(node a,node b) { return min(b.x,a.y) >=min(b.y,a.x);//贝尔曼规则条件的排序 } int main() { cout << "请输入机器零件的个数n:"<< endl; cin>> n; cout << "请依次输入每个机器零件在第一台机器上的加工时间x和第二台机器上的加工时间y:"<< endl; for (int i=0;i<n;i++) { cin >> T[i].x >> T[i].y; T[i].id=i+1; } sort(T,T+n,cmp); int f1=0; int f2=0; for (int i=0;i<n;i++) { f1+=T[i].x; f2=max(f1,f2)+T[i].y; } cout << "最优的机器零件加工顺序是:"<< endl; for (int i=0;i<n;i++) { cout << T[i].id ; } cout << endl; cout << "最优的零件加工时间是:"<< endl; cout << f2 << endl; return 0; }
4.结果测试
最后的时间复杂度是O(nlogn)。
最后的空间复杂度是O(n)。