首页 > 其他分享 >AcWing 1022. 宠物小精灵之收服

AcWing 1022. 宠物小精灵之收服

时间:2022-10-26 23:55:15浏览次数:91  
标签:体力 背包 1022 int 小精灵 v1 v2 110 AcWing

宠物小精灵之收服(二维费用背包问题)

原题链接:https://www.acwing.com/problem/content/1024/

思路

先做一个阅读理解

每一个小精灵只能收一次->01背包
接下来去考虑体积、价值是什么

经典的01背包只有一个限制:背包的体积

可以看出与经典的01背包不同,它有两个限制,一个是精灵球的数量,一个是皮卡丘的体力(这个题中可以剖析出来皮卡丘的体力不能为0,枚举体力时记得处理枚举边界)

dp思路:(仿照01背包)

状态表示:
	集合:f[i][j][u]表示的是从前i个精灵中选,权值1(体力v1[i])不能超过j权值2(球数v2[i])不能超过u的所有方案的集合
	属性:max(收集的精灵的数量的最大值)
状态转移:
		[1,2,3...,i,...,k]
	第i个精灵选与不选:
	不选:f[i][j][u] = f[i-1][j][u]
	选: if(j-v1[i] >= 0 && u-v2[i] >= 0) f[i][j][u] = max(f[i][j][u],f[i-1][j-v1[i]][u-v2[i]]+1) (体力和球的数量要足够)

代码


朴素版的内存超限了:

#include<iostream>
using namespace std;

const int N = 1010,M = 510;
int f[110][M][N];
int n,m,k; // 球数量,体力,精灵数量
int v1[110],v2[110]; // 体力v1,球数量v2

int main()
{
    cin >> n >> m >> k;
    for(int i = 1; i <= k;i ++) cin >> v2[i] >> v1[i];
    
    for(int i = 1;i <= k;i ++)
    {
        for(int j = 1;j < m; j ++)
        {
            for(int u = 1;u <= n; u ++)
            {
                f[i][j][u] = f[i-1][j][u];
                if(j-v1[i] >= 0 && u-v2[i] >= 0) f[i][j][u] = max(f[i][j][u],f[i-1][j-v1[i]][u-v2[i]]+1);
            }
        }
    }
    cout << f[k][m-1][n] << ' ';
    
    // 求收服这么多精灵时所消耗的最少体力
    int t = m;
    while(t > 0 && f[k][m-1][n] == f[k][t - 1][n]) t --;
    cout << m - t ; // 剩余体力就是m-t
    
    return 0;
}


优化版(仿照01背包优化):

#include<iostream>
using namespace std;

const int N = 1010,M = 510;
int f[M][N];
int n,m,k; // 球数量,体力,精灵数量
int v1[110],v2[110]; // 体力v1,球数量v2

int main()
{
    cin >> n >> m >> k;
    for(int i = 1; i <= k;i ++) cin >> v2[i] >> v1[i];
    
    for(int i = 1;i <= k;i ++)
    {
        for(int j = m - 1;j >= v1[i]; j --)
        {
            for(int u = n;u >= v2[i]; u --)
            {
                f[j][u] = max(f[j][u],f[j-v1[i]][u-v2[i]]+1);
            }
        }
    }
    cout << f[m-1][n] << ' ';
    
    // 求收服这么多精灵时所消耗的最少体力
    int t = m;
    while(t > 0 && f[m-1][n] == f[t - 1][n]) t --;
    cout << m - t ; // 剩余体力就是m-t
    
    return 0;
}

标签:体力,背包,1022,int,小精灵,v1,v2,110,AcWing
From: https://www.cnblogs.com/rdisheng/p/16830622.html

相关文章

  • Acwing 快速排序
    基于分治的思想,每次划分后,保证基准(x)前的数都比基准小,其后的树都比基准大即可。#include<iostream>usingnamespacestd;constintN=100010;intq[N];voidquic......
  • ACWing 4480 -- 二分&&双指针&&思维
    题目描述倒垃圾思路其实就是思维题,题意很简单,找到一个居民左侧和右侧(如果存在的话)的垃圾桶中最近的那个垃圾桶,然后让那个垃圾桶的计数器加一。从题目中挖掘的性质:左......
  • AcWing 271杨老师的照相排列
    思路\(1=<k<=5\),所以最多会有五个位置,五个位置分配人,即集合为f[a][b][c][d][e]表示五个位置各放了a,b,c,d,e个人的方法的数量,同时h[1]>=h[2]>=h[3]>=h[4]>=h[5],所......
  • ACWing - 4493 -- 思维题&&并查集&&dfs
    题目描述环形连通分量思路对于一个无向图中的简单环(环中边的数量等于点的数量),有一个很强的性质:每个点的度数等于\(2\)。那么我们只需要先找出所有的连通块,然后判......
  • AcWing168 生日蛋糕(剪枝)
    原题链接思路的话,就是暴搜加剪枝,中间有个放缩思路看这篇#include<bits/stdc++.h>#definepbpush_back#definefifirst#definesesecond#defineall(x)(x).begi......
  • AcWing107 超快速排序(树状数组找逆序对)
    原题链接思路求到底要和相邻元素交换几次,其实就是求逆序对的数量,有几对逆序对就要交换几次,因为只能相邻的之间交换(超快速排序?冒泡排序!)利用树状数组求逆序对大概想法......
  • AcWing 216. Rainbow的信号
    题目链接:​​传送门​​将权值转化成二进制来看,最多30位枚举每一位并且枚举一个右端点通过这个右端点判断有多少个左端点符合条件,累计贡献要注意单独讨论左端点等于右端......
  • AcWing 100. IncDec序列
    题目链接:​​传送门​​将序列转化成差分数列那么题目就变成了对一个数组可进行三种操作对两个元素一个加一一个减一或对一个元素加一或对一个元素减一其实后面两种操作......
  • AcWing 297. 赤壁之战
    题目链接:很容易想到一个dp:表示长度为,以结尾的上升子序列的个数转移的话就是从到枚举一个表示长度,再从到枚举一个,再从到枚举一个转移就是如果,表示可以接在后面,那么复杂度,......
  • AcWing 296. 清理班次2
    题目链接:​​传送门​​洛谷上的​​P4644[USACO05DEC]CleaningShifts​​​之前没发题解太高兴了数据结构优化dp的例题表示处理到处的最小花费拿一个线段树维护最小值......