刷题记录(NC16671 [NOIP2006]金明的预算方案,NC14699 队伍配置,NC235951 草药大师)

NC16671 [NOIP2006]金明的预算方案

题目链接

关键点:

1、动态转移选主件元件,对于dp[j],表示选则主件,和若干附加,不超过j元的最大价值

2、动态转移有四种情况:

(1)不选主件

(2)选主件,不选附件

(3)选主件,选一个附件(在花费允许的情况下)

(4)选主件,选两个附件(一个主件最多两个附件)(在花费允许的情况下)

dp[j] = max(dp[j], dp[j-mainw[i]]+mainv[i]);
            if (j-mainw[i]>=secw[i][1])
                dp[j] = max(dp[j], dp[j-mainw[i]-secw[i][1]]+mainv[i]+secv[i][1]);
            if (j-mainw[i]>=secw[i][2])
                dp[j] = max(dp[j], dp[j-mainw[i]-secw[i][2]]+mainv[i]+secv[i][2]);
            if (j-mainw[i]>=secw[i][2]+secw[i][1])
                dp[j] = max(dp[j], dp[j-mainw[i]-secw[i][2]-secw[i][1]]+mainv[i]+secv[i][2]+secv[i][1]);

用一个数组专门存主件的价值和花费,另一个二维数组存附件(对应主件)的价值花费

3、因为是一维的动态转移,因此我们将花费遍历倒过来

完整代码

# include <bits/stdc++.h>
using namespace std;
int n, m;
int mainw[70], mainv[70];
int secw[70][5], secv[70][5];
int dp[32000+10];
int main()
{
    cin>>n>>m;
    for (int i=1; i<=m; i++)
    {
        int v, p, q;
        cin>>v>>p>>q;
        if (!q)
        {
            mainw[i] = v;
            mainv[i] = p*v;
        }
        else
        {
            secw[q][0]++;
            secw[q][secw[q][0]] = v;
            secv[q][secw[q][0]] = v*p;
        }
    }
    for (int i=1; i<=m; i++)
    {
        for (int j=n; mainw[i]&&j>=mainw[i]; j--)
        {
            dp[j] = max(dp[j], dp[j-mainw[i]]+mainv[i]);
            if (j-mainw[i]>=secw[i][1])
                dp[j] = max(dp[j], dp[j-mainw[i]-secw[i][1]]+mainv[i]+secv[i][1]);
            if (j-mainw[i]>=secw[i][2])
                dp[j] = max(dp[j], dp[j-mainw[i]-secw[i][2]]+mainv[i]+secv[i][2]);
            if (j-mainw[i]>=secw[i][2]+secw[i][1])
                dp[j] = max(dp[j], dp[j-mainw[i]-secw[i][2]-secw[i][1]]+mainv[i]+secv[i][2]+secv[i][1]);
        }
    }
    cout<<dp[n]<<endl;
    
    
    return 0;
}

NC14699 队伍配置

题目链接

关键点:

1、对于从者的选择,我们只考虑选择5个,对于礼装,我们考虑选择不超过从者的个数

2、选择前i个从者和前j个礼装,我们可以利用滚动数组减去一维

3、设dp[i][j][k],表示在cost=i的前提下,选择j个从者,k个礼装的最大价值

4、我们可以先处理礼装(k)=0,情况下,最多选择5个从者的最大价值,注意cost要倒过来遍历(少了一维)

5、然后在输入礼装数据时,在遍历礼装的个数

完整代码:

# include <bits/stdc++.h>
using namespace std;
int dp[140][10][310];//代表i的cost下,选j个从者,装备k个礼装的最大价值
int ans, n, m, d;
int main()
{
    cin>>n>>m>>d;
    for (int i=1; i<=n; i++)
    {
        int x, y;
        cin>>x>>y;
        for (int i=d; i>=y; i--)
        {
            for (int j=1; j<=5; j++)
            {
                dp[i][j][0] = max(dp[i][j][0], dp[i-y][j-1][0]+x);
                ans = max(dp[i][j][0], ans);
            }
        }
    }
    for (int i=1; i<=m; i++)
    {
        int x, y;
        cin>>x>>y;
        for (int i=d; i>=y; i--)
        {
            for (int j=1; j<=5; j++)
            {
                for (int k=1; k<=j; k++)
                {
                    dp[i][j][k] = max(dp[i][j][k], dp[i-y][j][k-1]+x);
                    ans = max(dp[i][j][k], ans);
                }
            }
        }
    }
    cout<<ans<<endl;
    
    return 0;
}

NC235951 草药大师

题目链接

关键点:

1、因为最大的时间上限很大,直接遍历会超时,这里利用map来遍历,mp[i] = j,表示时间为i的情况下,最多采集的价值为j。可以发现在背包中,每次被更新的时间只会在所有草药(小于限定的s)中排列加减得到。

2、一维的map来代表dp数组,要将map倒着遍历

3、最后在所有的时间中取最大值即可

4、记得要初始化dp[0] = 0;

完整代码:

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, s;
map<ll, ll>mp;
ll t[110], v[110];
int main()
{
    cin>>n>>s;
    for (int i=1; i<=n; i++)
    {
        cin>>t[i]>>v[i];
    }
    mp[0] = 0;
    for(int i=1;i<=n;i++){
      for(auto it=rbegin(mp);it!=rend(mp);it++){
         if(it->first+t[i]<=s) 
           mp[it->first+t[i]]=max(mp[it->first+t[i]],mp[it->first]+v[i]);
         }
   }
    ll ans=0;
    for (auto it=mp.begin(); it!=mp.end(); it++)
        ans = max(it->second, ans);
    cout<<ans<<endl;
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值