杯子 + Kronican

杯子

Kronican

【题目描述】
重庆八中在80周年校庆的时候获捐n个杯子, 每个杯子有两个属性:一个是已装水量 ai,一个是可装水量 bi(ai <= bi)。
从一个杯子向另一个杯子倒 x 单位体积的水需要花费的时间是 x 秒。 现在用 n 个杯子中的 k 个来装所有的水, 求最小的 k, 以及最少花费的时间 t。

输入格式
第一行:一个正整数n(1 <= n <= 100),代表杯子的个数。
第二行:n个正整数,a1, a2, a3, a4 , … an(1 <= ai <= 100), ai表示第i 个杯子已装水量。
第三行:n个正整数,b1, b2, b3, b4 , … bn(1 <= bi <= 100),bi表示第i个杯子可装水量。
保证对于任意一个杯子,ai <= bi
输出格式
两个正整数,k 和 t,分别代表最少的杯子个数和最少花费的时间。

样例
样例1输入
4
3 3 4 3
4 7 6 5
样例1输出
2 6
样例2输入
2
1 1
100 100
样例2输出
1 1
样例3输入
5
10 30 5 6 24
10 41 7 8 24
样例3输出
3 11
数据范围与提示
在第一个样例中,可以把水从第1瓶倒到第2瓶。需要3秒钟,之后,第2瓶将含有 3 + 3 = 6 单位的水。然后可以把水从第4瓶倒进第2瓶,再倒进第3瓶:倒1个单位的水在第2瓶,倒2个单位的水在第3瓶,需要 1 + 2 = 3 秒 ,所以,所有水都会装在2个瓶子中,会花掉 3 + 3 = 6 秒来完成这件事情。

【思路+正解】

思考1:首先刚开始拿到这个题 我就联想到Day3的也是一道杯子题,用的是状压DP,那可把我激动地拿起一把大刀就往前冲,再一看n的范围 我的妈啊2^100是在搞笑吗? 立即pass状压DP

思考2:接着又看见求最小的k最少的t,min or max 脑子里的浆糊快速燃烧–>贪心!在这里插入图片描述
贪心一般是只维护一个,而这里有两个未知。啊,贪心再见,啊,贪心再见吧再见吧再见吧

思考3:那最近学的尺取?别白日做梦了骚年 有可能最优的方案是第二个和第三个杯子都满足k条件,但是第三个杯子的水多,这个时候第一个和第二个组合明显是更优的,pass

Finally
那么这狗时候你就凭你那驰骋坑底的经验,贪心一般都跟DP挂钩,既然不是状压DP,那就仔细寻找吧!但是又转念一想,平时练习都是先打暴搜,然后剪枝,接着记忆化,最后DP就善良登场了 blingling~~

我们先来解决一下k杯子的问题,显而易见,杯子的容量越大,可装的水就越多,在总水量一定时,我们可以sort杯子容量从大到小用一个for循环找到k的最小值

搜索

仙女的搜索还是颇有造诣的 不会做的题全都暴搜偏分(小声逼逼)
1.首先肯定有搜索的杯子编号i,选了几个杯子tot装水,选的杯子的总容量rest,选的所有杯子本来有的水的总和used (维护t)
2.肯定每个杯子有两种情况,要么被选,要么不选,时间复杂度就是(2^n)完爆啊!!
3.开始剪枝吧!既然我们可以开始就得到最小的s,那么这就可以成为一个剪枝条件–当所选杯子tot > k就可以return;到此就是45的暴力代码了;
核心代码如下

void dfs ( int x, int used, int resr, int tot ) {if ( x > n ) return;if ( tot > k ) return;if ( tot == k && used >= sum )  //sum是n个杯子装的所有水的总量result = min ( result, sum - ans );dfs ( x + 1, used, rest, tot );dfs ( x + 1, used+ cup[x + 1].a, rest+ cup[x + 1].b, tot + 1 );
}

4.为了更高的追求我们再来剪枝
思考一下为了让t越小的话,我们的搜索的used就要越大,那么当走到第i个杯子时,选定了tot个杯子且容量一定的时候,tot个杯子的原有水的总和大于了现在搜索的used就可以直接return—80分代码
5.因为这个鬼逼数据,有一个蜜汁优化就可以直冲100那个cs仙女也很迷啊
核心代码如下

void dfs ( int i, int used, int all, int tot ) {cs ++;if ( cs > 20000000 ) return;if ( tot > k ) return;if ( all >= sum ) {result = max ( result, used );return;}if ( i > n ) return;if ( dp[i][tot][all] == 0 || dp[i][tot][all] < used )dp[i][tot][all] = used;elsereturn;dfs ( i + 1, used + cup[i].a, all + cup[i].b, tot + 1 );dfs ( i + 1, used, all, tot );
}

当然如果到此就水过了这道,我的良心实在会痛
真正的Ac思路应该是用DP

DP

1.我们考虑i这个杯子,要么选要么不选,两种情况0/1,肯定是01背包问题了啊
2.挖掘到了这题所考察的知识点,马上大脑搜索01背包板子代码,dp[i][j]:表示循环处理到i号杯子时,可装水量为j的实际最大装水量 (注意区别:实际装水量=可装水量-选的杯子的原有总水量 这里要多加理解)
3.接下来就处理k的问题,前面说到k可以预先处理出来,那么我们就可以给这个DP多加一维k,dp[i][j][k]dp[i][j][k]dp[i][j][k]:表示处理到i号杯子时,一共选了k个杯子,可装水量为j的实际最大装水量 ,递推式:dp[i][j][k]=max(dp[i−1][j][k],dp[i−1][j−cup[i].b][k−1]+cup[i].a)dp[i][j][k] = max ( dp[i - 1][j][k], dp[i - 1][j - cup[i].b][k - 1] + cup[i].a )dp[i][j][k]=max(dp[i1][j][k],dp[i1][jcup[i].b][k1]+cup[i].a);
PS:三维好像会被卡空间 嘿嘿嘿
4.我们以前做的背包问题都可以减少一维i那么让我们也来将这个DP减少一维

码力有限的瞅瞅【代码实现】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 105
struct node {int a, b;
}cup[MAXN];
int n, sum, vol, need, ans, all;
int dp[MAXN * MAXN][MAXN];
bool cmp ( node x, node y ) {if ( x.b == y.b ) return x.a > y.a;else return x.b > y.b;
}
int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ ) {scanf ( "%d", &cup[i].a );sum += cup[i].a;}for ( int i = 1;i <= n;i ++ ) {scanf ( "%d", &cup[i].b );all += cup[i].b;}sort ( cup + 1, cup + n + 1, cmp );for ( int i = 1;i <= n;i ++ ) {vol += cup[i].b;if( vol >= sum ) {need = i;break;}}memset ( dp, -0x7f, sizeof ( dp ) );dp[0][0] = 0;for ( int i = 1;i <= n;i ++ )for ( int j = all;j >= cup[i].b;j -- )for ( int k = 1;k <= need;k ++ )dp[j][k] = max ( dp[j][k], dp[j - cup[i].b][k - 1] + cup[i].a );for ( int i = sum;i <= all;i ++ ) //要从可以装完所有水的sum开始枚举,不能从vol开始因为有可能vol>sum反而跳过了正解ans = max ( ans, dp[i][need] );printf ( "%d %d", need, sum - ans );return 0;
} 

拓展Party

上面的思考1时,我们提到过也是一道杯子的题,与此类似,看看我们能不能解决?
骚年拔剑吧
题目是:Kronican
在这里插入图片描述
【题目描述】
Mislav有N个无限体积的杯子,每一个杯子中都有一些水。Mislav想喝掉所有的水,但他不想喝超过K杯水。Mistrav能做的就是将一个杯子中的水倒入另一个杯子中。 不幸的是,挑选哪两个杯子进行倒水操作对Mislav来说很重要,因为并非所有的杯子都离他一样远。更准确地说,从i号杯子向j号杯子倒水所付出的代价为Cij。 帮助Mislav找到他需要付出的总代价的最小值。

输入格式
第一行输入包含整数N和K(1≤K≤N≤20)。表示水杯的总数和Mislav最多能喝多少杯。 接下来N行每行包含N个整数Cij(0≤Cij≤1e5)。第i+1行的第j个整数表示从第i个杯子第j个杯子倒水所需要付出的代价。保证Cii等于0。
输出格式
输出一个整数。表示Mislav需要付出的总代价的最小值。

样例
样例输入1
3 3
0 1 1
1 0 1
1 1 0
样例输出1
0
样例输入2
3 2
0 1 1
1 0 1
1 1 0
样例输出2
1
样例输入3
5 2
0 5 4 3 2
7 0 4 4 4
3 3 0 1 2
4 3 1 0 5
4 5 5 5 0
样例输出3
5
数据范围与提示:对于40%的数据,N≤10。

【正解】

拿到这道题,我想过建图连边,但是每两个就有一条显然不是,pass
贪心?也没有通向使用的贪心。那么dp?有点像,杯子最多有20个,数据这么小。woo状压dp嘛!欧拉欧拉!但是考试的时候我码不动状压,当时给我崩溃了orz,就只能含泪打个暴力骗骗小分,哼唧唧!
在这里插入图片描述
好了,为什么看得出是状压dp
首先n<=20就会想到状压或者搜索
又考虑到一杯水倒入其它杯后就不会有水倒入,显然是个0/1状态
因此设dp[s]为状态为s耗费的最小步数

倒水都是从一个有水的杯子到另一个有水的杯子
如果从有水到没水 那就做了无用功
把接受水的那个杯子里的水倒出去是没有用的
所以每次转移都枚举两个有水且不相同的两个杯子 进行倒水即可
定义0表示有水,1表示没有水

转移方程:dp[s+(1<<i)]=mindp[s]+c[i][j]dp[s+(1<<i)]=min{dp[s]+c[i][j]}dp[s+(1<<i)]=mindp[s]+c[i][j]
复杂度O(n2∗2n)O(n^2 * 2^n)O(n22n)不会炸放心搞

【代码实现】

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define MAXN 21
int n, k;
int c[MAXN][MAXN];
int dp[1 << MAXN];
//这是个好玩意儿!可以算出s的2进制的表示中有多少个1 
int cup ( int s ) { int cnt = 0;while ( s ) {s &= ( s - 1 );cnt ++;}return cnt;
}int main() {scanf ( "%d %d", &n, &k );for ( int i = 0;i < n;i ++ )for ( int j = 0;j < n;j ++ )scanf ( "%d", &c[i][j] );if ( n == k ) {printf ( "0" );return 0;}memset ( dp, 0x7f, sizeof ( dp ) );dp[0] = 0;for ( int s = 0;s < ( 1 << n );s ++ )for ( int i = 0;i <= n;i ++ )if ( ! ( s & ( 1 << i ) ) )for ( int j = 0;j < n;j ++ )if ( ! ( s & ( 1 << j ) ) && i != j )dp[s + ( 1 << i )] = min ( dp[s + ( 1 << i)], dp[s] + c[i][j] );int result = 0x7f7f7f7f;for ( int s = 0;s < ( 1 << n );s ++ )if ( cup ( s ) >= n - k ) result = min ( result, dp[s] );printf ( "%d", result );return 0;
}

【课后小料】
想写这个博客很久了,但一直卡着,大大的状压dp能力简直了,码得自己开始怀疑人生,但是wahahaha,我还是搞定了这个垃圾玩意儿!做个社会人(☆_☆)/~~
在这里插入图片描述
好了,有任何疑问欢迎留言,我是个闲人,不怕麻烦,我们再见哦~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318392.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【做题记录】 [HEOI2013]SAO

P4099 [HEOI2013]SAO 类型&#xff1a;树形 \(\text{DP}\) 这里主要补充一下 \(O(n^3)\) 的 \(\text{DP}\) 优化的过程&#xff0c;基础转移方程推导可以参考其他巨佬的博客(题解)。 令 \(f[x][p]\) 表示在以 \(x\) 为根的子树中&#xff0c;\(x\) 在拓扑序排在第 \(p\) 个时的…

CF25E-Test【AC自动机,bfs】

正题 题目链接:https://www.luogu.com.cn/problem/CF25E 题目大意 给出三个串&#xff0c;然后求一个最短的串包含这三个串。 1≤∣s1∣,∣s2∣,∣s3∣≤1051\leq |s_1|,|s_2|,|s_3|\leq 10^51≤∣s1​∣,∣s2​∣,∣s3​∣≤105 解题思路 把三个串状压&#xff0c;先跑出AC…

微软开源的Trill是什么?

以下是一篇15年的文章的译文&#xff1a;https://dwainegilmer.wordpress.com/2015/01/28/microsoft-trill-for-streaming-analytics-from-microsoft-research/当今许多大数据应用程序套件的重点是数据存储。它们是围绕狭窄范围的数据集设想和设计的&#xff0c;通常是为了组织…

剪纸游戏(博弈论)(SG函数)

文章目录题目描述解析题目描述 解析 本题的关键就是SG函数的定义 尝试了一些自己直观上可能对但题解没有使用的约定方法&#xff08;当然最后证明都是错的 。。。&#xff09;&#xff0c;对SG的理解更深刻了一些 SG0的含义是无法再移动换句话说也就是再移动也对败局于事无补&…

Fight against involution

题目&#xff1a; 对抗内卷&#xff08;大佬经常说别再卷了&#xff09; 有一门课程n个学生选&#xff0c;期末要写一篇论文每个同学写的字数有一个下限和一个上限&#xff0c;课程的成绩是按学生字数的排名来给分的&#xff0c;排名越高分数越高&#xff0c;每个同学都想得到…

【做题记录】 [JLOI2011]不等式组

P5482 [JLOI2011]不等式组 超烦人的细节题&#xff01;(本人调了两天 QAQ ) 这里介绍一种只用到一只树状数组的写法(离线)。 树状数组的下标是&#xff1a;所有可能出现的数据进行离散化之后的值。 其含义为&#xff1a;当 \(x\) 离散化后值为 \(i\) 时能满足的不等式个数为 \(…

[COCI2017-2018#5] Karte

[COCI2017-2018#5] Karte&#xff0c;简短的代码想到了就AC 这道题是SPJ放心搞 但是我的脑子里面的东西&#xff0c;不用我多说&#xff0c;你们就知道是水和面粉和成的 看招 题 【题目描述】 你有一副共有N张牌的牌&#xff0c;在第i张牌上会有一个数字ai表示在这张牌下面至…

YBTOJ:红与蓝(博弈论)

文章目录题目描述解析代码题目描述 解析 首先&#xff0c;这道题的情境对二人来说是不对称的&#xff0c;所以不太好使用SG函数来求解 但直观上也好考虑 利用树的递归性质可以求出每个节点的颜色是否确定 并确定根的颜色是否确定 如果确定是红就随便涂 确定是蓝就-1 关键在于不…

NWERC2020J-Joint Excavation【构造,贪心】

正题 题目链接:https://codeforces.com/gym/103049/problem/J 题目大意 nnn个点mmm条边的一张无向图&#xff0c;选出一条路径后去掉路径上的点&#xff0c;然后将剩下的点分成点数相等的两份使得两份之间没有边连接。 1≤n,m≤21051\leq n,m\leq 2\times 10^51≤n,m≤2105 解…

eShopOnContainers 看微服务④:Catalog Service

服务简介Catalog service&#xff08;目录服务&#xff09;维护着所有产品信息&#xff0c;包括库存、价格。所以该微服务的核心业务为&#xff1a;产品信息的维护库存的更新价格的维护架构模式先看代码结构&#xff08;下图&#xff09;。主要依赖&#xff1a;1、HealthCheck …

【CF 1195】Basketball Exercise/Submarine in the Rybinsk Sea (hard edition)/OpenStreetMap+二维单调队列滑动窗口模板

寡人认为C&#xff0c;E都是比较板的题 butD2也太ex了&#xff0c;大大是被那个mod精给弄疯了&#xff0c;我mod了那么多次还是炸了longlong orz 文章目录二维单调队列模板C&#xff1a;Basketball Exercise题目大意题解代码实现D2&#xff1a;Submarine in the Rybinsk Sea (…

Xor Transformation

题目&#xff1a; 给定一个X和Y&#xff0c;对于X每次可以选择一个A&#xff08;0<A<X&#xff09;&#xff0c;使得X X xor A&#xff0c;现在要求在5步内将X变为Y&#xff0c;请输出操作数目&#xff0c;以及每步的A 题解&#xff1a; 我一开始被题目给的样例个迷惑…

【做题记录】DP 杂题

P2577 [ZJOI2004]午餐 $\texttt{solution}$ 想到贪心&#xff1a; 吃饭慢的先打饭节约时间&#xff0c; 所以先将人按吃饭时间从大到小排序。 状态&#xff1a; \(f[i][j]\) 表示前 \(i\) 个人&#xff0c;在 \(1号\) 窗口打饭总时间 \(j\) &#xff0c;最早吃完饭的时间。 我们…

YBTOJ:方程的解(组合数学)(插板法)

文章目录题目描述解析代码题目描述 解析 第一感觉&#xff1a;啥都没感觉出来。。。 直接拿动态规划高精做的 但是只能拿40 重新分析一下这道题&#xff1a; g&#xff08;x&#xff09;首先可以拿快速幂很容易的求出来 问题就转化为了**把g(x)个东西分成k份的方案数 其实答案…

CF39C-Moon Craters【dp】

正题 题目链接:https://www.luogu.com.cn/problem/CF39C 题目大意 坐标轴上有nnn个圆&#xff0c;给出每个圆的位置cic_ici​和半径rir_iri​。 要求选出最多的圆使得他们不相交&#xff0c;求方案。 1≤n≤20001\leq n\leq 20001≤n≤2000 解题思路 转换为选出最多的不交区…

开源库Magicodes.Storage正式发布

说明Magicodes.Storage&#xff0c;是心莱科技团队提供的统一存储库&#xff0c;相关库均使用.NET标准库&#xff08;netstandard2.0&#xff09;编写&#xff0c;支持.NET Framework以及.NET Core。我们希望&#xff0c;使用了Magicodes.Storage之后&#xff0c;开发者可以很快…

P3389 【模板】高斯消元法

P3389 【模板】高斯消元法 题目&#xff1a; 给定一个线性方程组&#xff0c;对其求解 题解&#xff1a; 还没接触高斯消元时以为是什么神仙算法&#xff0c;接触后发现。。。就是把我们手算线性方程组的方法&#xff0c;写成了代码emm。。。 比如&#xff1a; x-2y3z6 4x…

【CF 1188 A1,B,C】Add on a Tree // Count Pairs // Array Beauty

传送门 这些天风也温柔&#xff0c;题也温柔 开车啦&#xff01; 文章目录A1&#xff1a;Add on a Tree题意翻译题解证明代码实现B&#xff1a;Count Pairs题意翻译题解代码实现C&#xff1a;Array Beauty题目描述题解代码实现A1&#xff1a;Add on a Tree 题意翻译 给定一棵…

eShopOnContainers 知多少[5]:EventBus With RabbitMQ

1. 引言事件总线这个概念对你来说可能很陌生&#xff0c;但提到观察者&#xff08;发布-订阅&#xff09;模式&#xff0c;你也许就很熟悉。事件总线是对发布-订阅模式的一种实现。它是一种集中式事件处理机制&#xff0c;允许不同的组件之间进行彼此通信而又不需要相互依赖&am…

USACO Section 4

前言 好久没更新这个系列了&#xff0c;最近闲的无聊写一下。有两题搜索懒得写了。 P2737 [USACO4.1]麦香牛块Beef McNuggets https://www.luogu.com.cn/problem/P2737 解题思路 先只考虑a1a_1a1​&#xff0c;假设我们拼出了www&#xff0c;那么一定能拼出wka1wka_1wka1​…