贪心(临项交换)+01背包,蓝桥云课 搬砖

2024-05-30 03:28

本文主要是介绍贪心(临项交换)+01背包,蓝桥云课 搬砖,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

0搬砖 - 蓝桥云课 (lanqiao.cn)


二、解题报告

1、思路分析

将物品按照w[i] + v[i]升序排序然后跑01背包就是答案

下面证明:(不要问怎么想到的,做题多了就能想到,和谷歌那道能量石一样的套路)
对于物品i, j, 前面已经有了W

现:w[i] + v[i] <= w[j] + v[j]

且j 能排在前面 ,我们要推出 i 是否也能在前面

因为j在前面所以,v[j] >= W   v[i] >= W + w[j]

结合[i] + v[i] <= w[j] + v[j]可推出:v[j] - w[i] >= v[i] - w[j] >= W

进而推出:v[j] >= W + w[i]
故i在前面时,v的价值大于前面的重量和,得证

那么对于任何一个最优解,我们按照w[] + v[]升序排序,不影响最优解的合法性,仍然得到最优解

换句话说,我们在原问题的集合中找到了一个小集合:w[] + v[]升序

且小集合中存在最优解

那么我们在这个小集合中跑01背包就能得到最优解

所以排序后跑01背包就行

注意倒序枚举时,容量初始为w[] + v[]

因为v[] >= m - w[] => m <= v[] + w[]

2、复杂度

时间复杂度: O(nlogn + Σ(v[i] + w[i]))空间复杂度:O(n)

3、代码详解

#include <bits/stdc++.h>const int N = 1010;int n, tot, m, f[200010];struct node {int w, v;bool operator < (const node& x) const {return v + w <= x.v + x.w;}
} nodes[N];int main () {std::cin >> n;for (int i = 0; i < n; i ++ ) std::cin >> nodes[i].w >> nodes[i].v, m += nodes[i].w;std::sort(nodes, nodes + n);for (int i = 0; i < n; i ++ )for (int j = std::min(m, nodes[i].w + nodes[i].v); j >= nodes[i].w; j -- )f[j] = std::max(f[j], f[j - nodes[i].w] + nodes[i].v);std::cout << *std::max_element(f, f + m + 1);return 0;
}

这篇关于贪心(临项交换)+01背包,蓝桥云课 搬砖的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1015447

相关文章

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

使用C语言实现交换整数的奇数位和偶数位

《使用C语言实现交换整数的奇数位和偶数位》在C语言中,要交换一个整数的二进制位中的奇数位和偶数位,重点需要理解位操作,当我们谈论二进制位的奇数位和偶数位时,我们是指从右到左数的位置,本文给大家介绍了使... 目录一、问题描述二、解决思路三、函数实现四、宏实现五、总结一、问题描述使用C语言代码实现:将一个整

poj2576(二维背包)

题意:n个人分成两组,两组人数只差小于1 , 并且体重只差最小 对于人数要求恰好装满,对于体重要求尽量多,一开始没做出来,看了下解题,按照自己的感觉写,然后a了 状态转移方程:dp[i][j] = max(dp[i][j],dp[i-1][j-c[k]]+c[k]);其中i表示人数,j表示背包容量,k表示输入的体重的 代码如下: #include<iostream>#include<

hdu2159(二维背包)

这是我的第一道二维背包题,没想到自己一下子就A了,但是代码写的比较乱,下面的代码是我有重新修改的 状态转移:dp[i][j] = max(dp[i][j], dp[i-1][j-c[z]]+v[z]); 其中dp[i][j]表示,打了i个怪物,消耗j的耐力值,所得到的最大经验值 代码如下: #include<iostream>#include<algorithm>#include<

csu(背包的变形题)

题目链接 这是一道背包的变形题目。好题呀 题意:给n个怪物,m个人,每个人的魔法消耗和魔法伤害不同,求打死所有怪物所需的魔法 #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>//#include<u>#include<map

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

usaco 1.3 Barn Repair(贪心)

思路:用上M块木板时有 M-1 个间隙。目标是让总间隙最大。将相邻两个有牛的牛棚之间间隔的牛棚数排序,选取最大的M-1个作为间隙,其余地方用木板盖住。 做法: 1.若,板(M) 的数目大于或等于 牛棚中有牛的数目(C),则 目测 给每个牛牛发一个板就为最小的需求~ 2.否则,先对 牛牛们的门牌号排序,然后 用一个数组 blank[ ] 记录两门牌号之间的距离,然后 用数组 an

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

uva 10130 简单背包

题意: 背包和 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>