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,可见没有这么极端的数据吧。
或者通过下述状态方程减少所需内存
- bool dp[21][20000001]; //dp[i][j]: cow[1...i] considered, whether stack height of j exists
#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;
}
}
}
}
参考
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;
}
}