参考:
余祥宣, 崔国华, 邹海明. 计算机算法基础.3版[M]. 华中科技大学出版社, 2006.
C++带有期限和效益的单位时间的作业排序贪心算法JS
“更快”的作业排序问题,使用不相交集合的 UNION和FIND算法,可以将JS的计算时间降低到数量级接近О(n)
使用压缩规则的查找算法FIND 伪码
Procedure FIND(i)
//查找含有元素i的树根,使用压缩规则去压缩由i到根j的所有结点//
j←i
while PARENT(j)> 0 do //找根//
j←PARENT(j)
k←i
while (k≠j) do //压缩由i到根j的结点 //
t←PARENT(k)
PARENT(k)←j
k←t
repeat
return (j)
end FIND
C++实现FIND
int FIND(int *parent, int i)
{//查找含有元素i的树根,使用压缩规则去压缩由i到根j的所有结点
int j, k, t;
j = i;
while (parent[j] > 0) j = parent[j];//找根
k = i;
while (k != j) {//压缩由i到根j的结点
t = parent[k];
parent[k] = j;
k = t;
}
return j;
}
使用加权规则的合并算法UNION 伪码
Procedure UNION(i,j)
//使用加权规则合并根为i和j的两个集合,i≠j//
//PARENT(i)=-COUNT(i),PARENT(j)=-COUNT(j)//
integer i,j,x;
x←PARENT(i)+ PARENT(j)
if PARENT(i)> PARENT(j)
then PARENT(i) ←j //i的结点少//
PARENT(j) ←x
else PARENT(j) ←i //j的结点少//
PARENT(i) ←x
endif
end UNION
C++实现UNION
void UNION(int *parent, int i, int j)
{//使用加权规则合并根为i和j的两个集合
int x;
x = parent[i] + parent[j];
if (parent[i] > parent[j]) {//i的结点少
parent[i] = j;
parent[j] = x;
}
else {//j的结点少
parent[j] = i;
parent[i] = x;
}
}
作业排序的一个更快算法FJS 伪码
Line procedure FLS(D,n,b,J,k)
//找最优解J=J(1),…J(k),假定p1≥p2≥…pn,b=min{n,max{D(i)}}//
integer b,D(n),J(n),F(0:b),P(0:b)
for i←0 to n do //将树置初值//
F(i) ←i; P(i) ← -1
Repeat
k←0 //初始化J//
for i←1 to n do //使用贪心规则//
j←FIND(min(n,D(i)))
if F(j)≠0 then k←k+1;J(k) ←i //选择作业i//
l←FIND(F(j)-1); call UNION(l,j)
F(j) ←F(l)
endif
C++实现FJS。这里把伪码里FJS函数的参数k改为了Q[ ]以存放作业的顺序
//F[ ]用于存放最大期限值,J[ ]用于存放最优解,Q[ ]用于存放作业的调度次序
int FJS(int *D, int n, int b, int *J, int *Q)
{//找J(n)的最优解,并返回最优解的个数
int i, j, l, k;
int *F = new int[n];
int *P = new int[n];
for (i = 0; i <= b; i++) {//将树置初值
F[i] = i;
P[i] = -1;
}
k = 0;//初始化J
for (i = 1; i <= n; i++)
{//使用贪心规则
j = FIND(P, MIN(n, D[i]));
if (F[j] != 0)
{//选择作业i
k = k + 1;
J[k] = i;
Q[F[j]] = i;
l = FIND(P, F[j] - 1);
UNION(P, l, j);
F[j] = F[l];
}
}
return k;//返回最优解的个数
}
带期限和效益的作业排序的一个更快算法FJS的完整实现
输入文件为文档文本hwt.txt。这三个是测试文档,第一行是作业量,第二行开始的第一列是效益P,第二列是期限D。
#include<iostream>
#include<fstream>
using namespace std;
int MIN(int n, int m)
{//求n和m的最小值
if (n > m) return m;
else return n;
}
int MAXMUM(int i, int j)
{//求i和j的最大值
if (i > j) return i;
else return j;
}
int MAX(int *D, int i, int j)
{//D(1:n)是含有n个元素数组,求出D(i,j)中的最大值并返回
int max, mid, max1, max2;
if (i == j) max = D[i];
else
if (i == j - 1)
if (D[i] < D[j]) max = D[j];
else max = D[i];
else {
mid = (i + j) / 2;
max1 = MAX(D, i, mid);
max2 = MAX(D, mid + 1, j);
max = MAXMUM(max1, max2);
}
return max;
}
void SORT(int P[], int D[], int start, int end)//按效益大到小排序
{
for (int i = start + 1; i <= end; i++)
{
int item = P[i];
int item_d = D[i];
int j = i - 1;
while (j >= start && item > P[j])
{
P[j + 1] = P[j];
D[j + 1] = D[j];
j--;
}
P[j + 1] = item;
D[j + 1] = item_d;
}
}
int FIND(int *parent, int i)
{//查找含有元素i的树根,使用压缩规则去压缩由i到根j的所有结点
int j, k, t;
j = i;
while (parent[j] > 0) j = parent[j];//找根
k = i;
while (k != j) {//压缩由i到根j的结点
t = parent[k];
parent[k] = j;
k = t;
}
return j;
}
void UNION(int *parent, int i, int j)
{//使用加权规则合并根为i和j的两个集合
int x;
x = parent[i] + parent[j];
if (parent[i] > parent[j]) {//i的结点少
parent[i] = j;
parent[j] = x;
}
else {//j的结点少
parent[j] = i;
parent[i] = x;
}
}
//F[ ]用于存放最大期限值,J[ ]用于存放最优解,Q[ ]用于存放作业的调度次序
int FJS(int *D, int n, int b, int *J, int *Q)
{//找J(n)的最优解,并返回最优解的个数
int i, j, l, k;
int *F = new int[n];
int *P = new int[n];
for (i = 0; i <= b; i++) {//将树置初值
F[i] = i;
P[i] = -1;
}
k = 0;//初始化J
for (i = 1; i <= n; i++)
{//使用贪心规则
j = FIND(P, MIN(n, D[i]));
if (F[j] != 0)
{//选择作业i
k = k + 1;
J[k] = i;
Q[F[j]] = i;
l = FIND(P, F[j] - 1);
UNION(P, l, j);
F[j] = F[l];
}
}
return k;//返回最优解的个数
}
int main()
{
int n, p, d, i, b, k;
ifstream in("hwt.txt");
in >> n;//作业数
int *P = new int[n];//效益
int *D = new int[n];//期限
int *J = new int[n];//解集
int *Q = new int[n];//顺序
//P[0] = 0, D[0] = 0;
for (int i = 1; i <= n; i++)
{
in >> p >> d;
P[i] = p;
D[i] = d;
}
cout << "i\tP[i]\tD[i]\t Before Sort" << endl;
for (int i = 1; i <= n; i++)
{
cout << i << "\t" << P[i] << "\t" << D[i] << "\t" << endl;
}
cout << endl;
SORT(P, D, 1, n);
cout << "i\tP[i]\tD[i]\t After Sort" << endl;
for (int i = 1; i <= n; i++)
{
cout << i << "\t" << P[i] << "\t" << D[i] << "\t" << endl;
}
cout << endl;
b = MIN(n, MAX(D, 1, n));
for (i = 1; i <= b; i++)
Q[i] = -1;
k = FJS(D, n, b, J, Q);
cout << "J[i]\tP[i]\tD[i]\t 本问题的最优解" << endl;
for (i = 1; i <= k; i++)
cout << J[i] << "\t" << P[J[i]] << "\t" << D[J[i]] << endl;
cout << endl;
cout << "Q[i]\tP[i]\tD[i]\t Result" << endl;
for (i = 1; i <= b; i++)
if (Q[i] != -1)
cout << Q[i] << "\t" << P[Q[i]] << "\t" << D[Q[i]] << endl;
cout << endl;
int sum = 0;
for (int i = 1; i <= b; i++)
{
if (Q[i] != -1) {
cout << Q[i] << " -> ";
sum += P[Q[i]];
}
}
cout << "\tsum = " << sum << endl;
for (int i = 1; i <= b; i++)
if (Q[i] != -1)
cout << D[Q[i]] << "(" << P[Q[i]] << ")" << " -> ";
system("pause");
return 0;
}
运行结果