【动态规划】任务分配问题

这篇博客探讨了一种零件加工时间分配问题,目标是使两台机床完成加工的时间尽可能同步。作者提供了两种解决方案,一种是利用动态规划的方法,类似于0-1背包问题,另一种是暴力枚举所有可能的分配方式。通过这两种算法,可以找到最小的完工时间差异。文章还给出了具体的C++代码实现,并给出了样例输入和输出。
摘要由CSDN通过智能技术生成

题目来自贵大OJ


题目描述:给定n个零件需要的加工时间,分配到两台机床上加工,使得两台机床完成加工的时间尽可能同步。设计一个穷举搜索算法求解该问题。例如,有3个零件,加工时间分别为2、5和3,那么把加工时间为2、3的两个零件分配到一台机床上加工,把加工时间为5的零件分配到另一台机床上加工,两台机床能同时完工。

输入描述:每组数据的第一行是一个整数n (1 <= n <= 20)代表零件的数量。接下来有n行,每一行一个整数代表该零件所需的加工时间。

输出描述:对于每组测试数据,输出两台机床完工时间的最小差异。

样例输入

10
205 157 133 111 100 91 88 59 47 23

8
635 853 401 868 335 435 704 754

样例输出
0
3


【分析问题】对原问题稍加抽象,问题可以转化为:现有n个数,和为sum,分成两部分,使它们差的绝对值最小。即其中一部分元素的和<=sum/2,且是最接近sum/2的元素集合。

【解题思路】利用动态规划的解法。这其实类似于0-1背包问题,n个数相当于重量和价值相等的物品,要放入容量为sum/2的背包中。

使用一维数组dp存储,dp[j]表示前i个数和j最接近的累加值。

状态方程:dp[j]=max(dp[j],dp[j-num[i]]+num[i])

#include<iostream>
#include<cmath>
using namespace std;

int main()
{
    int num[21]; //0位置空出来
    int n,half,sum=0;
    cin>>n;
    for(int i=1;i<=n;i++){
       cin>>num[i];
        sum+=num[i];
    }
    half=sum/2;
    int dp[half+1]={0};

    for(int i=1;i<=n;i++)
        for(int j=half;j>=num[i];j--)
            dp[j]=max(dp[j],dp[j-num[i]]+num[i]);
            //dp[j]为num[i]不累加时的最大值
            //dp[j-num[i]]+num[i]为num[i]累加时的最大值
    
    int res=sum-2*dp[half];
    cout<<res;
}

俗话说,大力出奇迹。下面顺便附上暴力法的代码。

【思路】下面利用了n位二进制数来表示数的所有状态。 规定二进制数位1代表在机器1,0代表在机器二。当二进制第一位为1时,累加进变量mach(表示机器1处理的零件),用sum减去两倍mach,即可得到差值。

#include<iostream>
#include<cmath>
using namespace std;

int main()
{
    int n,sum=0;
    int min=32767;//使min尽可能大,防止结果大于min
    int num[20]={0};
    cin>>n;
    for(int i=0;i<n;i++){
       cin>>num[i];
        sum+=num[i];
    }
    
    for(int i=0;i<pow(2,n);i++)//从全0到全1
    {
        int t=i,mach=0;
        for(int j=n-1;j>=0;j--,t>>=1)
            mach+=(t%2)?num[j]:0;//当二进制最后一位为1,累加
        int tmp=abs(sum-2*mach);//求差值
        min=(min>tmp)?tmp:min;
    }

    cout<<min;
}
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值