题意:有几只乌龟,每只乌龟有一定的重量与力量。每只乌龟可以背小于它力量的重量(包括它自身的重量)。问最多一共可以有多少只乌龟叠在一起。
可以证明,将力量大的乌龟放在下面可以得到一个更优的状态。因此在dp之前应先将所有乌龟按力量大小排好序,力量小的在前面。(证明可见这个网页)
1.用dp[i][j]表示从前 i 只乌龟中选出 j 只可以得打的最小总重量。
转移方程为:如果dp[i-1][j-1]+t[i].w <=t[i].s,dp[i][j] = min( dp[i-1][j-1]+t[i].w, dp[i-1][j] ); 如果不等,则dp[i][j] = dp[i-1][j];
#include <iostream>
#include <cstdio>
#include <string.h>
#include <cmath>
#include <algorithm>
using namespace std;
int dp[5650][5650];
typedef struct
{
int w, s;
}tur;
tur t[5650];
int n;
bool comp( tur a, tur b)
{
if( a.s <b.s||(a.s==b.s&& a.w< b.w))
return true;
return false;
}
int main()
{
n=0;
while( scanf("%d%d",&t[n].w,&t[n].s )!=EOF )n++;
sort( t, t+n, comp);
int i,j;
memset( dp, 0x7f, sizeof( dp));
for( i=0; i<=n; i++)
dp[i][0] =0;
for( i=1; i<=n; i++)
for( j=1;j<=i; j++)
{
if(dp[i-1][j] <dp[i][j])
dp[i][j] =dp[i-1][j];
if( dp[i-1][j-1]+t[i-1].w <=t[i-1].s &&dp[i-1][j-1]+t[i-1].w<dp[i][j] )
dp[i][j] =dp[i-1][j-1]+t[i-1].w;
}
for( i=n; i>=0; i--)
if( dp[n][i]<(1<<30))
break;
printf("%d\n",i);
return 0;
}
2.用滚动数组做,dp[j]表示选出j只乌龟的最小总重量。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
struct turtle
{
int w,s;
}tur[5650];
int dp[5650];
bool comp(turtle a, turtle b)
{
if( a.s< b.s||(a.s==b.s && a.w<b.w ))
return true;
return false;
}
int main()
{
int n=1,i,j;
while( cin>>tur[n].w >>tur[n].s ) n++;
sort(tur+1, tur+n,comp);
n--;
for( i=1; i<=n; i++)
dp[i] =1000000000;
dp[0]=0;
int ans=1;
for( i=1; i<=n; i++)
for( j=n; j>=1; j--)
{
if( dp[j-1]+tur[i].w<=tur[i].s)
dp[j] =min( dp[j], dp[j-1]+tur[i].w);
if( dp[j]<1000000000 )
ans =max( j,ans);
}
cout <<ans<<endl;
return 0;
}