用01背包解决石子归并问题

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


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值