C++ 贪心算法带期限和效益的作业排序的一个更快算法FJS

参考:
余祥宣, 崔国华, 邹海明. 计算机算法基础.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。
hwt.txt

#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;
}

运行结果
FJS运行结果

  • 9
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值