题目来自贵大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最接近的累加值。
状态方程:
#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;
}