动态规则 01背包问题 poj 1837 3628

poj 3628 

#include <iostream>
#include <stdio.h>
#include<cstring>

// i放进v容量的袋子里,所能取得的最大值
// F[i-1][v] 意思是当前物品i不放进去,
// F[i-1][v-c[i]] 是当前物品放进去,则前i-1个物品放进容易V-c[i]容量内能取得的最大值F[i-1][v-c[i]]
//F[i][v] =max{ F[i-1][v],F[i-1][V-c[i]] + w[i] }

using namespace std;

#define MAX_V (20+1)
#define MAX_F (20000000+1) sum-B的最大值
	int N[MAX_V];
	int n,B,C;
	int F[MAX_V][MAX_F];

int main()
{

	while(cin>>n>>B)
	{
		int sum = 0;
		for(int i=1;i<=n;i++)
		{
			cin>>N[i];
			sum += N[i];
		}

		C = sum - B;

		memset(F,0,sizeof(F));
		for(int i=1;i<=n;i++)
		{
			F[i][0] = 0;
		}
		for(int i=1;i<=n;i++)
		{
			for(int c=1;c<=C;c++)
			{
				if(N[i] <= c)
				{
					//可以放进去,尝试要不要放进去
					F[i][c] = max( F[i-1][c] , F[i-1][c-1] + N[i]);
				}
			}
		}

		int maxc = -1;
		for(int i=1;i<=n;i++)
		{
			if(F[i][C] > maxc)
				maxc = F[i][C];
		}
		
		cout<<(sum-maxc) - B<<endl;

	}
}

F数据占据1600MB内存,MLE。O(n*C)

 01背包占用内存优化

#include <iostream>
#include <stdio.h>
#include<cstring>

// i放进v容量的袋子里,所能取得的最大值
// F[i-1][v] 意思是当前物品i不放进去,
// F[i-1][v-c[i]] 是当前物品放进去,则前i-1个物品放进容易V-c[i]容量内能取得的最大值F[i-1][v-c[i]]
//F[i][v] =max{ F[i-1][v],F[i-1][V-c[i]] + w[i] }

using namespace std;

#define MAX_V (20+1)
#define MAX_F (20000000+1)
int N[MAX_V];
int n,B,C;
//int F[MAX_V][MAX_V];

int F[MAX_F];

int main()
{
	while(cin>>n>>B)
	{
		int sum = 0;
		for(int i=1;i<=n;i++)
		{
			cin>>N[i];
			sum += N[i];
		}

		C = sum - B;

		memset(F,0,sizeof(F));
		for(int i=1;i<=n;i++)
		{
			for(int c=C;c>=N[i];c--)
			{
				//if(N[i] <= c)
		//		{
					//可以放进去,尝试要不要放进去
					//F[i][c] = max( F[i-1][c] , F[i-1][c-1] + N[i]);
					//F[c] = max(F[c],F[c-1] + N[i]);
					F[c] = max(F[c],F[c-N[i] ] + N[i]); //这里抽象物品 所占空间与价值是相同的(特殊情况)


		//		}
			}
		}

		int maxc = -1;
	//	for(int i=1;i<=n;i++)
	//	{
	//		if(F[i][C] > maxc)
	//			maxc = F[i][C];
	//	}
		for(int c=1;c<=C;c++)
			if(F[c] > maxc)
				maxc = F[c];
		
		cout<<(sum-maxc) - B<<endl;

	}
}

依然占用80M
网上有的直接定义C最大为100万的
5 16
3
1
3
1000000
1000000

这份测试数据就core dump,RE了。但提交竟然AC,可见没有这么极端的数据吧。

或者通过下述状态方程减少所需内存

  1. bool dp[21][20000001];     //dp[i][j]: cow[1...i] considered, whether stack height of j exists  
http://chuanwang66.iteye.com/blog/1473896


#include <iostream>
#include <stdio.h>
#include<cstring>

// i放进v容量的袋子里,所能取得的最大值
// F[i-1][v] 意思是当前物品i不放进去,
// F[i-1][v-c[i]] 是当前物品放进去,则前i-1个物品放进容易V-c[i]容量内能取得的最大值F[i-1][v-c[i]]
//F[i][v] =max{ F[i-1][v],F[i-1][V-c[i]] + w[i] }

using namespace std;

#define MAX_V (20+1)
#define MAX_F (20000000+1)
int N[MAX_V];
int n,B,C;
//int F[MAX_V][MAX_V];

bool F[MAX_F]; //F[i][j] 表示通过选取1->i号cow能否达到j的高度
//F[i][j] = F[i-1][j] || F[i-1][j-N[i]]

int main()
{
	while(cin>>n>>B)
	{
		int sum = 0;
		memset(N,0,sizeof(N));
		memset(F,0,sizeof(F));

		for(int i=1;i<=n;i++)
		{
			cin>>N[i];
			sum += N[i];
		}

		C = sum ;

		F[0] = true;

		for(int i=1;i<=n;i++)
		{
			for(int c=C;c>=0;c--)
			{
				//F[c] = F[c] || F[c-N[i]] //c-N[i] may be negative
				//so

				if(F[c] == true)
					continue;
				if(N[i] <= c)
					F[c] = F[c - N[i]];
				//if(N[i] <= c)
		//		{
					//可以放进去,尝试要不要放进去
					//F[i][c] = max( F[i-1][c] , F[i-1][c-1] + N[i]);
					//F[c] = max(F[c],F[c-1] + N[i]);
					//F[c] = max(F[c],F[c-N[i] ] + N[i]); //这里抽象物品 所占空间与价值是相同的(特殊情况)


		//		}
			}
		//	F[N[i]] = true;
		}

	//	for(int i=1;i<=n;i++)
	//	{
	//		if(F[i][C] > maxc)
	//			maxc = F[i][C];
	//	}
//		int maxc = -1;
//		for(int c=1;c<=C;c++)
//			if(F[c] > maxc)
//				maxc = F[c];
//		
//		cout<<(sum-maxc) - B<<endl;
		for(int sb=B;sb<=C;sb++)
		{
			if(F[sb] == true)
			{
				cout<< sb - B<<endl;
				break;
			}
		}

	}
}



poj 1837 
参考
http://blog.youkuaiyun.com/lyy289065406/article/details/6648094

#include <iostream>
#include <stdio.h>
#include <cstring>

using namespace std;

int C,G;
#define MAX_V (20+1)
#define MAX_F (15000+1) // 20*25*15 *2 //成2是避免负下标
int CV[MAX_V],GV[MAX_V];
int F[MAX_V][MAX_F];// F[i][j]为挂了i个砝码时,使得平衡度为j的挂法数量
//F[i][j] = F[i-1] [ j - G[i]*C[k]  第i个砝码挂在了第k个钩子上
//为避免负坐标 状态方程为 F[i][j+G[i]*C[k] ] +=  F[i-1][j]
//初始F[0][7500] = 1; //表示初始状态什么都不挂也是一种平衡点
int main()
{
	while(cin>>C>>G)
	{
		for(int i=1;i<=C;i++)
			cin>>CV[i];

		for(int i=1;i<=G;i++)
			cin>>GV[i];

		memset(F,0,sizeof(F));

		F[0][7500] = 1;

		for(int i=1;i<= G;i++)
			for(int j=1;j<= MAX_F;j++)
			{
				for(int k=1;k<= C;k++)
					F[i][j+GV[i] * CV[k]] += F[i-1][j];
			}


		//int sum=0;
		//for(int i=0;i<=G;i++)
		//	sum += F[i][7500];

		cout<<F[G][7500]<<endl;

	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值