1171 Big Event in hdu 解题报告
题目不难。背包问题,上限是总和的一半。可以转化成01背包问题,也可以用多重背包解决。下面是笔者的AC代码:
#include <iostream> using namespace std; char dp[250001]; int v[51]; int m[101]; int main() { int i,j,k,n,max,t,sum; while(cin>>n) { if(n<0) continue; for(sum=i=0;i<n;i++) { cin>>v[i]>>m[i]; sum+=v[i]*m[i]; } memset(dp,0,sizeof(dp)); dp[0]=1; max=sum/2; for(i=0;i<n;i++) for(j=max;j>=0;j--) if(dp[j]) for(k=1;k<=m[i];k++) dp[j+v[i]*k]=1; for(i=sum/2;i>=0;i--) if(dp[i]) break; cout<<sum-i<<' '<<i<<endl; } }
最后先输出sum-i的原因是sum/2<=sum-sum/2.
额,虽然过了,但是时间差强人意,93MS。在网上找到的另外一份代码,基本是模板了,我改了一点点,时间是31MS,贴在下面了。
#include<stdio.h> #include<string.h> int dp[200001],w[101],num[101],V; inline int max(int a,int b) { return a>b?a:b; } void ZeroOnePack(int cost,int weight) { for(int i=V;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } void CompletePack(int cost,int weight) { for(int i=cost;i<=V;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } void MultiplePack(int cost,int weight,int amount) { if(amount*cost>=V) { CompletePack(cost,weight); return ; } int k=1; while(k<amount) { ZeroOnePack(cost*k,weight*k); amount-=k; k+=k; } ZeroOnePack(amount*cost,amount*weight); } int main() { int n,i,sum; while(scanf("%d",&n),n>0) { sum=0; for(i=1;i<=n;i++) { scanf("%d %d",&w[i],&num[i]); sum+=w[i]*num[i]; } V=sum>>1; memset(dp,0,sizeof(*dp)*(V+1)); for(i=1;i<=n;i++) MultiplePack(w[i],w[i],num[i]); printf("%d %d\n",sum-dp[V],dp[V]); } return 0; }
我会把代码改改的。。。31MS的那份代码的多重背包的函数中用了2分的思想,这可能就是原因吧。虽然有模板,我还是喜欢自己敲敲。
将我的代码用上二分。。。时效46MS,估计有误差。0MS的代码又是怎样的呢?
#include <iostream> using namespace std; int dp[250001]; int s[51]; int num[51]; int main() { int i,j,k,max,up,up2,n,t,tn; while(~scanf("%d",&n)) { if(n<0) continue; dp[up=max=0]=1; for(i=0;i<n;i++) { scanf("%d%d",s+i,num+i); up+=s[i]*num[i]; } up2=up/2; for(i=0;i<n;i++) { for(k=1;k<num[i];k*=2) { num[i]-=k; for(j=max;j>=0;j--) { if(dp[j]&&(t=j+s[i]*k)<=up2) { dp[t]=1; if(max<t) max=t; } } } { for(j=max;j>=0;j--) { if(dp[j]&&(t=j+s[i]*num[i])<=up2) { dp[t]=1; if(max<t) max=t; } } } } printf("%d %d\n",up-max,max); } }