背包贪心,比赛时只考虑了两端都出头,其实还有不出头和只有一端出头的情况,这里的u的数量就是对应上面三种情况
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=1000+10; typedef long long int ll; typedef pair<ll,ll> pp; pp a[maxn]; int n,l,t; ll dp[4*maxn][5];//因为防止浮点数,所以要开到4000 int main() { while(~scanf("%d",&t)) { for(int ii=1; ii<=t; ii++) { ll maxi=0; scanf("%d%d",&n,&l); l=l*2;//防止浮点数 for(ll i=0; i<n; i++) { scanf("%lld%lld",&a[i].first,&a[i].second); a[i].first=a[i].first*2;//同上 maxi=max(maxi,a[i].second);//防止一个 } memset(dp,0,sizeof(dp)); for(int i=0; i<n; i++) for(int j=l; j>=a[i].first/2; j--) { for(int u=0; u<=2; u++) {//只找组合,并不需要排序 if(u>0) { if(j>=a[i].first) dp[j][u]=max(dp[j][u],dp[j-a[i].first][u]+a[i].second); dp[j][u]=max(dp[j][u],dp[j-a[i].first/2][u-1]+a[i].second);//最神奇的地方,每种最终容器盛满只能从0到1经过1次,从0到2经过两次,正好对应几次出头 } else if(j>=a[i].first) dp[j][u]=max(dp[j][u],dp[j-a[i].first][u]+a[i].second); } } printf("Case #%d: ",ii); printf("%lld\n",max(maxi,dp[l][2])); } } return 0; }