【2016级学长的邀请赛】Problem B 空門蒼的祭典

传送门

  • 空門蒼负责的祭典人手不够了,现在她需要求助你会。可惜的是,你会人手也不够了,所以你会会长yyh需要女装来纳新。

现有n个职位,每个职位只能纳一个人,这届有m个萌新,每个萌新只能胜任一个职位,每个萌新都有自己的实力值与需求值,你会会长可以通过女装来满足他们的需求值,但你会会长最多也只能满足s的需求值(即纳到的萌新需求值≤s),在社长的能力范围之内,要让纳到的萌新实力值之和最大,问最大值为多少。

输入

第一行分别为 n,m,s
接下来有 m 行,每行有三个数字 x,y,z 分别代表这个萌新能胜任的位置(以数字 1-n 来表示),实力值,需求值

输出

输出为一个数字,代表最大的实力值之和

输入样例

3 9 10
1 4 2
1 7 5
1 8 10
2 6 2
2 7 2
2 8 2
3 4 6
3 7 7
3 8 2

输出样例

23

提示

对于20%的数据, m<=20, n<=20, s<=100
对于50%的数据, m<=500, n<=500, s<=1000
对于100%的数据, m<=5000, n<=5000, s<=5000


我相信你一眼就看出来这是道DP题

所以只要用分组背包的思路做就可以轻松AC了

分组背包和普通背包的差别:

这个问题变成了每组物品有若干种策略:

是选择本组的某一件,还是一件都不选。

也就是说设 f [ k ] [ j ] 表示前 k 组物品花费费用 j 能取得的最大权值,则有:

f[k][j]=max(f[k−1][j],f[k−1][j−c[i]]+w[i]∣物品i属于组k)

核心伪代码:

for (所有的组k)
    for (int j = V; j >= 0; j--)
        for (所有属于组k的i)
            f[j] = max{f[j], f[j - w[i]] + v[i]}

注意这里的三层循环的顺序, f o r ( j . . . 0 )

这一层循环必须在 for (所有的 i 属于组 k)之外。

这样才能保证每一组内的物品最多只有一个会被添加到背包中。

另外,显然可以对每组内的物品应用完全背包中“一个简单有效的优化”。

  • 小结

分组的背包问题将彼此互斥的若干物品称为一个组,这建立了一个很好的模型。

不少背包问题的变形都可以转化为分组的背包问题(例如有依赖的背包),由分组的背包问题进一步可定义“泛化物品”的概念,十分有利于解题。

以下是AC代码:

//By Mitruha
//Date : 2020 10 23
//分组背包 
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 5010;

int v[Maxn], w[Maxn];
int a[Maxn][Maxn];
int opt[Maxn];
int n, m, s, group;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m >> s;
    for(int i = 1;i <= m; i++)
    {
        cin >> group >> w[i] >> v[i];
        a[group][++a[group][0]] = i;
    }

    for(int i = 0; i < s; i++)
        for(int j = m ; j >= 0 ; j--)
            for(int k = 1;k <= a[i][0]; k++)
                if(j - v[a[i][k]] >= 0)
                    opt[j] = max(opt[j], opt[j - v[a[i][k]]] + w[a[i][k]]);

    cout << opt[m] << "\n";
    return 0;
}
posted @ 2020-12-05 10:49  MitruHa  阅读(50)  评论(0编辑  收藏  举报