独立任务最优调度问题 (动态规划dp)

参考:https://blog.csdn.net/LDUtyk/article/details/53995281

独立任务最优调度问题:

使用dp[i][j]数组表示的是第i个作业时,机器a花费不小于j时间的前提下,机器b完成作业i所需的最少时间。
当机器a在时间j的时候小于a[i]时,当然只能由b机器完成,
如果时间j大于a[i],那么考虑是由a还是b机器完成才好,
给a处理的话,b花费时间是dp[i-1][j-a[i]],
给b处理的话,b花费时间是dp[i-1][j]+b[i-1];
从中取小值作为dp[i][j]的值。

当所有工作分配完成之后,找出所有工作用时最少的时间。
所有工作完成的时间就是a机器与b机器耗费时间取大值。再从中选择小值作为结果。

分析:

当完成k个作业,设机器A花费了x时间,机器B所花费时间的最小值肯定是x的一个函数,设F[k][x]表示机器B所花费时间的最小值(注意,这是B机器所花费的时间,即当B机器停机时的时间点)。则有

F[k][x]=Min{ F[k-1][x]+b[k], F[k-1][x-a[k]] };

其中,F[k-1][x]+b[k]表示第k个作业由机器B来处理(完成k-1个作业时机器A花费的时间仍是x,前提就是A机器停机的时间是x),F[k-1][x-a[k]]表示第k个作业由机器A处理(完成k-1个作业时机器A花费的时间是x-a[k])。

那么x(表示A机器的停机时间)、F[k][x](表示B机器的停机时间)两者取最晚停机的时间,也就是两者中最大的时间,是在AB在此时间中完成k任务最终的时间:Max(x, F[k][x])。而机器A花费的时间x在此期间是一个变量,其取值可以是即x=0,1,2……x(max),(理论上x的取值是离散的,但为编程方便,设为整数连续的)由此构成了点对较大值序列。要求整体时间最短,取这些点对较大值序列中最小的即是。

理解难点在于B是A的函数表达式,也即动态规划所在。花点时间,看懂表达式,加上思考,理解了这点一切OK,后面的编程实现完全依据这个思想。先用前两个任务的枚举示例来帮助理解。

数据输入:

6
2 5 7 10 5 2
3 8 4 11 3 4

代码:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 100;
int minn = 0x3f3f3f3f;
int a[maxn];		//机器A处理每个作业的时间 
int b[maxn];		//机器B处理每个作业的时间 
int dp[maxn][maxn]; //表示完成i个作业且机器A花费j时间的条件下机器B所花费时间的最小值	  	 

int main()  
{  
	int n, suma = 0;
	cin >> n;
    for(int i = 0; i < n; i++)
    {
    	cin >> a[i];
    	suma += a[i];
    }
	for(int i = 0; i < n; i++)
	{
		cin >> b[i];
	}
	for(int i = 1; i <= n; i++)
	{
		for(int j = 0; j <= suma; j++)
		{
			if(j < a[i - 1])//机器a在时间j的时候小于a[i]时,作业i只能由机器b完成 
				dp[i][j] = dp[i - 1][j] + b[i - 1];		
			else if(dp[i - 1][j - a[i - 1]] > dp[i - 1][j] + b[i - 1])	//选择较小时间 
				dp[i][j] = dp[i - 1][j] + b[i - 1];	//作业i由机器b处理 
			else
				dp[i][j] = dp[i - 1][j - a[i - 1]]; //作业i由机器a处理	
		}
	}  
    int temp;
    for(int i = 0; i <= suma; i++)
    {
    	temp = dp[n][i] > i? dp[n][i] : i;
		if(temp < minn)			//机器a与b所花时间取个大值  
		minn = temp; 			//求出最小  
    }
    cout << "最短时间为: " << minn << endl;  
    return 0;  
}  
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这是一个经典的动态规划问题,可以使用C语言实现。以下是一种可能的解决方案: 1. 定义状态:设f(i,j)表示前i个任务放在j张加密卡上的最小花费。 2. 状态转移方程:考虑第i个任务,它可以独立放在一张加密卡上,也可以与前面的任务一起放在一张加密卡上。因此,有以下两种情况: 1) 第i个任务独立放在一张加密卡上,那么前i-1个任务就需要放在j-1张加密卡上,此时状态转移方程为: f(i, j) = min(f(i-1, j), f(i-1, j-1)) + cost(i) 2) 第i个任务与前面的任务一起放在一张加密卡上,那么前i-1个任务就需要放在j张加密卡上,此时状态转移方程为: f(i, j) = f(i-1, j) + cost(i) 其中,cost(i)表示第i个任务的花费。 3. 边界条件:当i=1时,只需要考虑前1个任务放在1张加密卡上的情况,即f(1,1)=cost(1)。当j=1时,只能将前i个任务都放在1张加密卡上,即f(i,1)=f(i-1,1)+cost(i)。 4. 最终答案:最小花费为min(f(n,1), f(n,2), f(n,3), f(n,4)),其中n为总任务数。 下面是C语言代码实现: ```c #include <stdio.h> #include <stdlib.h> #define MAX_TASKS 100 #define MAX_CARDS 4 int min(int a, int b) { return a < b ? a : b; } int main() { int n, i, j, k, cost[MAX_TASKS + 1], f[MAX_TASKS + 1][MAX_CARDS + 1]; // 读入任务数和每个任务的花费 scanf("%d", &n); for (i = 1; i <= n; i++) { scanf("%d", &cost[i]); } // 初始化边界条件 for (i = 1; i <= n; i++) { f[i][1] = f[i-1][1] + cost[i]; } for (j = 1; j <= MAX_CARDS; j++) { f[1][j] = cost[1]; } // 动态规划求解 for (i = 2; i <= n; i++) { for (j = 2; j <= MAX_CARDS; j++) { f[i][j] = f[i-1][j] + cost[i]; for (k = 1; k < i; k++) { f[i][j] = min(f[i][j], f[k][j-1] + cost[i]); } } } // 输出最小花费 int ans = f[n][1]; for (j = 2; j <= MAX_CARDS; j++) { ans = min(ans, f[n][j]); } printf("%d\n", ans); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值