http://blog.csdn.net/w397090770/article/details/8028945
题目:有一堆石头质量分别为W1,W2,W3...WN.(W<=100000)现在需要你将石头合并为两堆,使两堆质量的差为最小。
这道题目可以用01背包问题来解决。即求出和最接近sum/2的一个子集 令f(i, j)表示前i个元素中和最接近j的子集的和(有点绕),则有: f(i, j) = max( f(i-1, j), f(i-1, j-a[i])+a[i] ) ,其中a数组是用来存储所有石头的质量的。
源码如下:
以下是参考代码:
#define N1 8
int W1;
int* Table[N1+1];
int Weight[N1+1]={-1,3,41,25,6,2,3,7,10};
int* Path[N1+1];
void tet()
{
int sum=0;
for(int i=1;i<N1+1;i++)
{
sum+=Weight[i];
}
cout<<"sum:"<<sum<<endl;
W1=sum>>1;
for(int i=0;i<N1+1;i++)
{
Table[i]=(int*)malloc(sizeof(int)*(W1+1));
Path[i]=(int*)malloc(sizeof(int)*(W1+1));
memset(Table[i],0,sizeof(int)*(W1+1));
memset(Path[i],0,sizeof(int)*(W1+1));
}
for(int i=0;i<N1+1;i++)
{
for(int j=0;j<W1+1;j++)
{
Table[i][j]=-1;
Path[i][j]=0;
}
}
for(int i=0;i<N1+1;i++)
Table[i][0]=0;
for(int j=0;j<W1+1;j++)
Table[0][j]=0;
}
int Calculate()
{
tet();
for(int i=1;i<N1+1;++i)
{
for(int j=1;j<W1+1;j++)
{
Table[i][j]=Table[i-1][j];
if(j>=Weight[i])
{
int t1=Table[i-1][j];
int t2=Table[i-1][j-Weight[i]]+Weight[i];
if(t2>t1)
Path[i][j]=1;
Table[i][j]=t2>t1?t2:t1;
}
}
}
int i=N1,j=W1;
while(i>0&&j>0)
{
if(Path[i][j]==1)
{
j-=Weight[i];
cout<<Weight[i]<<" ";
}
i--;
}
cout<<endl;
return Table[N1][W1];
}
int main()
{
//tet();
cout<<Calculate();
return 0;
}
也可以参考原文的代码:
#include <stdio.h>
#define N 5
// Author: 397090770
// E-mail: wyphao.2007@163.com
// 转载请注明。
int do_(int *arr, int m){
if(arr == NULL){
return;
}
int i = 0, j = 0;
int c[N + 1][100];//这个相当于上面的f(i,j)
for(i = 0;i < N + 1; i++)//初始化
for(j = 0; j < 100; j++)
c[i][j]=0;
for(i = 1; i < N + 1; i++)
for(j = 1; j< m + 1; j++){
if(arr[i - 1] <= j){
if(arr[i - 1] + c[i-1][j-arr[i - 1]] > c[i-1][j])
c[i][j] = arr[i - 1] + c[i-1][j-arr[i - 1]];
else
c[i][j] = c[i-1][j];
}else
c[i][j] = c[i-1][j];
}
//printf("%d\n", c[N][m]);
return c[N][m];//最后一个就是最优值
}
int main(){
int arr[N] = {
/*1, 5, 7, 8, 9, 6, 3, 11, 20, 17*/
5, 8, 13, 27, 14
};
int sum = 0;
int i = 0;
for(i = 0; i < N; i++){
sum += arr[i];
}
int result = do_(arr, sum / 2);
printf("%d\n", sum - 2 * result);
return 0;
}