AC Hdu 2602 Bone Collector 非常常规的01背包问题,用一维和二维数组都可以做,一维快相当多。
#include<stdlib.h>
#include<ctype.h>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include <string>
#include <sstream>
using namespace std;
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
int main()
{
int t;
scanf("%d",&t);
int a[1000],c[1000],dp[10000];
while(t--)
{
int n,v;
scanf("%d%d",&n,&v);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&c[i]);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
for(int j=v;j>=0;j--)
{
if(j-c[i]>=0)
dp[j]=max(dp[j],dp[j-c[i]]+a[i]);
}
printf("%d\n",dp[v]);
}
}
AC Poj 3624 Charm Bracelet 赤裸裸的01背包问题。
#include "iostream"
#include "math.h"
using namespace std;
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
int main()
{
int n,m;
int a[40000],b[40000];
int dp[40000];
while( cin>>n>>m )
{
for(int i=0;i<n;i++)
cin>>a[i]>>b[i];
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
for(int j=m;j>=0;j--)
{
if(j-a[i]>=0)
dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
}
cout<<dp[m]<<endl;
}
}
AC Hdu 2546 饭卡 n种菜选若干种使剩下的钱最少,背包容量是开始时的钱,物品体积是菜的价格,状态转移时记录答案。
#include "iostream"
#include "cstdlib"
#include "cstring"
#include "cmath"
#include "algorithm"
using namespace std;
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
int main()
{
int i,j,m,n,a[2000],d[2000];
while( scanf("%d",&n)!=EOF && n )
{
for(i=0;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
sort(a,a+n);
memset(d,0,sizeof(d));
if(m>=5)
{
{
for(i=0;i<n-1;i++)
for(j=m-5;j>=a[i];j--)
{
d[j]=max(d[j],d[j-a[i]]+a[i]);
}
}
printf("%d\n",m-d[m-5]-a[n-1]);
}
else
printf("%d\n",m);
}
}
//先计算出m-5块钱在n-1个物品内最多买多少钱的菜,然后再减去最大价格的菜
AC Hdu 2955 Robberies (推荐 ) 抢劫方案最优问题,需要一个简单地转换,我们求的是不被抓的概率而非被抓的概率,各个银行的储蓄总和为背包容量,体积为单个银行 的储蓄,价值为不被抓概率。
#include "iostream"
#include "cstdlib"
#include "cstring"
#include "cmath"
#include "algorithm"
using namespace std;
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
double p;
int n,t,sum;
int m[1000];
double q[1000];
double dp[10000];
int main()
{
scanf("%d",&t);
while(t--)
{
int ss;
sum=0;
scanf("%lf %d",&p,&n);
for(int i=0;i<n;i++)
{
scanf("%d%lf",&m[i],&q[i]);
q[i]=1.0-q[i];
sum+=m[i];
}
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=0;i<n;i++)
for(int j=sum;j>=0;j--)
{
if(j-m[i]>=0)
dp[j]=max(dp[j],dp[j-m[i]]*q[i]);
}
for(int i=0;i<=sum;i++)
{
int big=-1;
if( dp[i]>big && ( dp[i]>=(1-p)) )
{
big=dp[i];
ss=i;
}
}
printf("%d\n",ss);
}
}
AC Poj 2184 Cow Exhibition(推荐 ) 变形的 01 背包,其实问题的本质是保证智商和幽默感和不为负数情况下的最大和。智商属性体积,幽默感属性为价值,问题转换为求体积大等于 0 时的体积、价值总和。
#include "stdio.h"
#include "stdlib.h"
#include "algorithm"
#include "iostream"
#include "math.h"
#include "string.h"
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
int a[110],b[110];
int dp[200000];
int main()
{
int n;
int t=10000;
while(scanf("%d",&n)!=EOF )
{
for(int i=0;i<n;i++)
scanf("%d%d",&a[i],&b[i]);
memset(dp,-10000,sizeof(dp));
dp[t]=0;
for(int i=0;i<n;i++)
{
if(a[i]<0 && b[i]<0 )
continue ;
else if(a[i]>0)
{
for(int j=199999;j>=a[i];j--)
dp[j]=max(dp[j-a[i]]+b[i],dp[j]);
}
else
{
for(int j=0;j<200000+a[i];j++)
dp[j]=max(dp[j-a[i]]+b[i],dp[j]);
}
}
int ans=0;
for(int i=t;i<200000;i++)
if(dp[i]>0)
ans=max(ans,i-t+dp[i]);
printf("%d\n",ans);
}
return 0;
}
AC Hdu 3466 Proud Merchants 与顺序有关的01背包,先按q-p排序再来处理,难想容易敲。
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include <string>
#include <sstream>
using namespace std;
int dp[100000];
int max (int a,int b)
{
if (a>b )
return a ;
else
return b;
}
struct Ac
{
int p;
int q;
int v;
}ac[1000000];
bool cmp(Ac ss ,Ac sss)
{
return ( ss.q-ss.p ) < ( sss.q- sss.p ) ;
}
int main()
{
int n,m;
int t,s ,k;
while(scanf("%d%d",&n,&m)!=EOF )
{
for(int i=0;i<n;i++)
scanf("%d%d%d",&ac[i].p,&ac[i].q,&ac[i].v);
memset(dp,0,sizeof(dp));
sort(ac,ac+n,cmp);
for (int i=0;i<n;i++)
for (int j=m;j>=0;j--)
{
if ( j-ac[i].q>=0 )
dp[j]=max (dp[j],dp[j-ac[i].p]+ac[i].v);
}
printf("%d\n",dp[m]);
}
return 0;
}
AC Hdu 1114 Piggy-Bank 简单多重背包,但当成01背包来暴力也完全没有问题
#include "iostream"
#include "cstdlib"
#include "cstring"
#include "cmath"
#include "algorithm"
using namespace std;
int min(int a,int b)
{
if(a>b)
return b;
else
return a;
}
int main()
{
int t,ok,k;
int e,f,n,s;
int p[1000],w[1000],dp[10000];
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&e,&f);
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&p[i],&w[i]);
memset(dp,1000000,sizeof(dp));
dp[0]=0;
s=f-e;
ok=0;
for(int i=0;i<n;i++)
for(int j=0;j<=s;j++)
{
if(j-w[i]>=0)
dp[j]=min(dp[j],dp[j-w[i]]+p[i]);
}
if(dp[s]!=1000000 && dp[s]<1000000)
printf("The minimum amount of money in the piggy-bank is %d.\n",dp[s]);
else
printf("This is impossible.\n");
}
}
AC Hdu 1059 Dividing 简单多重背包,体积为硬币数,价值为币值,可用二进制处理成01背包求解,可用30对num进行优化。
//多重背包
//HDU 1059
//题意:价值分别为1,2,3,4,5,6的物品的个数分别为 a[1],a[2],````a[6]
//问能不能分成两堆价值相等的
#include<stdio.h>
#include<string.h>
int a[7];
int f[120005];
int v,k;
void ZeroOnePack(int cost,int weight)//cost 为费用, weight 为价值
{
for(int i=v;i>=cost;i--)
if(f[i-cost]+weight>f[i]) f[i]=f[i-cost]+weight;
}
void CompletePack(int cost,int weight)
{
for(int i=cost;i<=v;i++)
if(f[i-cost]+weight>f[i]) f[i]=f[i-cost]+weight;
}
void MultiplePack(int cost ,int weight,int amount)
{
if(cost*amount>=v) CompletePack(cost,weight);
else
{
for(int k=1;k<amount;)
{
ZeroOnePack(k*cost,k*weight);
amount-=k;
k<<=1;
}
ZeroOnePack(amount*cost,amount*weight);
}
}
int main()
{
int tol;
int iCase=0;
while(1)
{
iCase++;
tol=0;
for(int i=1;i<7;i++)
{
scanf("%d",&a[i]);
tol+=a[i]*i;//总价值数
}
if(tol==0) break;
if(tol%2==1)
{
printf("Collection #%d:\nCan't be divided.\n\n",iCase);
continue;
}
else
{
v=tol/2;
memset(f,0,sizeof(f));
for(int i=1;i<7;i++)
MultiplePack(i,i,a[i]);
if(f[v]==v)
printf("Collection #%d:\nCan be divided.\n\n",iCase);
else printf("Collection #%d:\nCan't be divided.\n\n",iCase);
}
}
return 0;
}
AC Hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 标题超长超简单的多重背包,可用01背包求解。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,m;
int c[110],w[110],num[110],dp[110];
void ZeroOnePack(int cost, int weight)
{
for(int i = n; i >= cost; i--)
dp[i] = max(dp[i],dp[i-cost]+weight);
}
void CompletePack(int cost, int weight)
{
for(int i = cost; i <= n; i++)
dp[i] = max(dp[i],dp[i-cost]+weight);
}
void MultiplePack(int cost, int weight, int amount)
{
if(cost * amount >= n)
{
CompletePack(cost,weight);
}
else
{
int k = 1;
while(k < amount)
{
ZeroOnePack(k*cost,k*weight);
amount -= k;
k = k << 1;
}
ZeroOnePack(amount*cost,amount*weight);
}
}
int main()
{
int test;
scanf("%d",&test);
while(test--)
{
scanf("%d %d",&n,&m);
for(int i = 1; i <= m; i++)
{
scanf("%d %d %d",&c[i],&w[i],&num[i]);
}
memset(dp,0,sizeof(dp));
for(int i = 1; i <= m; i++)
{
MultiplePack(c[i],w[i],num[i]);
}
printf("%d\n",dp[n]);
}
return 0;
}