【upc】取石子 | 背包方案DP

题目大意:

 

n+e最近在研究取⽯⼦游戏。
有n堆⽯⼦,第i堆⽯⼦有ai个,最多取m堆⽯⼦(保证m≤n),请问在要求总⽯⼦数不超过k的情况下最多能取多少⽯⼦。

输入

第⼀⾏输⼊3个数字n,m,k,意义见上。
第⼆⾏n个数字,依次表示ai。

输出

输出⼀个数字,表示你的答案。

样例输入 Copy

4 3 5
1 1 2 3

样例输出 Copy

5

提示

取第1、2、4组⽯⼦,或3,4组⽯⼦,刚好是5个。

数据分为A、B、C三组,各占30%、30%、40%。
对于A组数据,1≤m≤n≤10,1≤k≤1000,1≤ai≤100
对于B组数据,1≤m≤n≤20,1≤k≤108,1≤ai≤106
对于C组数据,1≤m≤n≤200,1≤k≤2500,1≤ai≤50

 

题目思路:

 

这是一个纯面向数据编程的题目...

1.两个数据k是小于2500的,那么很容易想到用背包的方案dp可以解决,令dp[i][k]的0与1取值 ,代表i个物品是否可以组成重量为k的方案[不求方案数的话只用01表示即可]。那么很容易得到状态转移方程:

\large dp[i+1][k+num[i]]|=dp[i][k]

每次来一个物品更新一下就可以了~

2.至于要过B组数据,k在1e8数量级显然,dp已经不可用了,但是n很小,所以直接暴力就可以啦~复杂度:\large 2^n*n

 

附一下AC代码:

#include 
using namespace std;
typedef long long ll;
const ll INF=1000000000000005;
const ll maxn=5e5+5;
const int mod=998244353;
ll n,m,p;
ll num[maxn];
ll dp[2500][2500];//i个物品是否可以组成重量为k的物品
ll mx=0;
void work(int x)
{
    for(int i=min(mx,m);i>=0;i--)
        for(int k=0;k+num[x]<=p;k++)
            dp[i+1][k+num[x]]|=dp[i][k];
    mx++;
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&p);
    for(int i=1;i<=n;i++) scanf("%lld",&num[i]);
    if(p<=2500)
    {
        ll maxl=0;
        dp[0][0]=1;
        for(int i=1;i<=n;i++) work(i);
        for(int i=1;i<=m;i++)
            for(int k=1;k<=p;k++)
                if(dp[i][k]) maxl=max(maxl,(ll)k);
        printf("%lld\n",maxl);
    }
    else
    {
        ll maxl=0;
        for(int i=0;i<(1<>(k-1)&1)
                {
                    cnt++;
                    sum+=num[k];
                }
            if(cnt<=m&&sum<=p)
                maxl=max(maxl,sum);
        }
        printf("%lld\n",maxl);
    }
    return 0;
}
/**
5 3 5
4 5 6 1 2
***/

 

 

 

你可能感兴趣的:(upc经典题目及题解整理,背包dp)