小奇取石子
题解
本题需要根据数据范围的不同来考虑。
对于第一个30%的数据,打个暴力即可。
对于第二个30%的数据,一看,就是状压dp,将每一堆石子压个状态就行了。
对于第三个40%的数据,打个朴素dp就行了,表示表示i个石子选择的最少堆数。
源码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
typedef long long LL;
int n,m,k,a[205];
int dp[2505],ans,dp1[(1<<20)+5];
#define gc() getchar()
template<typename _T>
inline void read(_T &x)
{
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
int main()
{
//freopen("stone.in","r",stdin);
//freopen("stone.out","w",stdout);
read(n);read(m);read(k);
for(int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+n+1);
if(k<=2500)
{
memset(dp,INF,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++)
for(int j=k;j>=a[i];j--)
dp[j]=min(dp[j],dp[j-a[i]]+1);
for(int i=k;i>=0;i--)
if(dp[i]<=m)
{
printf("%d",i);
return 0;
}
}//朴素
else
{
int ans=0;
for(int i=1;i<(1<<n);i++)
{
int tmp=0;
for(int j=1;j<=n;j++)
if(i&(1<<j-1))
tmp++;
for(int j=1;j<=n;j++)
if(i&(1<<j-1))
dp1[i]=max(dp1[i],dp1[i^(1<<j-1)]+a[j]);
if(tmp<=m&&dp1[i]<=k) ans=max(dp1[i],ans);
}
printf("%d",ans);
return 0;
}//状压
return 0;
}
谢谢!!!