DP刷题Day2

Q1: 金明的预算方案

思路分析:
  开心的金明的稍稍变式,本题有个限制就是如果要买归类为附件的物品,必须先买该附件所属的主件,同时每个主件只有 0 个、1 个或 2 个附件。也就是说,对于每一个大类(主件以及其附件),我们有这么几种选择:①不选这个主件。②只选这个主件。③选这个主件,并且选附件1。④选这个主件,并且选附件2。⑤选这个主件,并且选附件1和附件2。同时,我们也只能选择其中的一种。于是这个题便变成了分组背包问题。

参考代码:

#include <bits/stdc++.h>

using namespace std;

#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define pb push_back

const int N = 100, M = 32005;

int n, m;
int a[65], b[65];
vector<int> c[65], l[N];
int v[N], w[N], f[M], idx = 1;



inline void slove()
{
    cin >> m >> n;
    for(int i = 1; i <= n; ++ i)
    {
        int x, p; cin >> a[i] >> x >> p;
        b[i] = a[i] * x;
        if(p == 0) c[i].pb(i);
        else c[p].pb(i);
    }
	// 预处理出每一组
    for(int i = 1; i <= n; ++ i)
    {
        int len = c[i].size();
        if(len == 0) continue;
        else if(len == 1)
        {
            int x = c[i][0], p = idx;
            v[idx] = a[x], w[idx] = b[x], l[p].pb(idx);
            ++ idx;
        }
        else if(len == 2)
        {
            int x = c[i][0], y = c[i][1], p = idx;
            v[idx] = a[x], w[idx] = b[x], l[p].pb(idx);
            ++ idx;
            v[idx] = a[x] + a[y], w[idx] = b[x] + b[y], l[p].pb(idx);
            ++ idx;
        }
        else
        {
            int x = c[i][0], y = c[i][1], z = c[i][2], p = idx;
            v[idx] = a[x], w[idx] = b[x], l[p].pb(idx);
            ++ idx;
            v[idx] = a[x] + a[y], w[idx] = b[x] + b[y], l[p].pb(idx);
            ++ idx;
            v[idx] = a[x] + a[z], w[idx] = b[x] + b[z], l[p].pb(idx);
            ++ idx;
            v[idx] = a[x] + a[y] + a[z], w[idx] = b[x] + b[y] + b[z], l[p].pb(idx);
            ++ idx;
        }
    }
    // 完全背包
    for(int i = 1; i < idx; ++ i)
    {
        if(l[i].size() == 0) continue;
        for(int j = m; j; -- j)
            for(auto k : l[i])
                if(j >= v[k])
                    f[j] = max(f[j], f[j - v[k]] + w[k]);
    }
    cout << f[m] ;
}

int main()
{
    IO;
    int _;
    _ = 1;
    //cin >> _;
    while(_ --)
    {
        slove();
    }
    return 0;
}

Q2: 最大约数和

思路分析:
  01 背包裸题,我们记 S D ( x ) SD(x) SD(x) x x x 的所有约数之和(除 x x x 本身),那么这里 x x x S D ( x ) SD(x) SD(x) 分别对应01 背包中的物品体积和价值,题目中的 S S S 即是最大体积。

参考代码:

#include <bits/stdc++.h>

using namespace std;

#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'

const int N = 1005;

int n;
int w[N], f[N];

inline void slove()
{
    cin >> n;
    for(int i = 1; i <= n; ++ i)
    {
        int sum = 0;
        for(int x = 1; x <= i / x; ++ x)
        {
            if(i % x == 0)
            {
                sum += x;
                if(x != i / x)
                    sum += (i / x);
            }
        }
        sum -= i;
        w[i] = sum;
    }
    for(int i = 1; i <= n; ++ i)
        for(int j = n; j >= i; -- j)
            f[j] = max(f[j], f[j - i] + w[i]);
    cout << f[n] ;
}

int main()
{
    IO;
    int _;
    _ = 1;
    //cin >> _;
    while(_ --)
    {
        slove();
    }
    return 0;
}

End:
  今天的题解分享就到这里结束啦,如果有更好的解法或者思路,欢迎大家评论区留言交流!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值