在TechFlow学长的公众号里发现一道挺有意思的CF算法题,现在利用学长的思路学习一下

题目链接:https://codeforces.com/contest/1418/problem/C

题意

这道题的题意也很有意思,背景也是游戏。说是有一天你和你的基友一起在家打游戏,这个游戏一共有n个boss。这些boss的难度不同,有些boss简单,有些boss困难。你的技术要比基友的好一些,你们两人轮流打boss。

游戏规定每次进行游戏最少打1个boss,最多打两个boss。由于你的实力更好,你可以战胜所有的boss。但是你的基友比较菜,只能打得过简单的boss,如果碰上hard模式的boss就只能氪金。基友的钱也是钱,你们希望在尽量少氪金的前提下把游戏通关。现在已知所有boss的难易情况并且基友先开始游戏,请问在最佳策略下,最少需要氪金多少次?

样例

首先给定一个数字t,表示测试数据组数。对于每组数据,给定一个数字n,表示boss的数量。接着给定n个0或者1的整数,0表示boss是简单模式,1表示是困难模式。要求返回一个数字,即最少的氪金次数。其中

\[n≤2⋅10^5
\]
input:
8
1 0 1 1 0 1 1 1 output:
2

样例解释

基友先杀1和2两个boss,氪金一次。

“我”杀3和4号boss

基友杀5号boss

“我”杀6和7号boss

基友击杀8号boss,氪金一次,总共氪金两次。

题解

这道题我们最先想到的可能就是贪心,比如我们可以想到一种贪心策略,就是每次基友杀怪的时候先杀1个,然后看第二个是0还是1,如果是0的则一起杀了,否则不杀留给“我”。

我们可以用之前介绍过的等价判断法来判断一下这个贪心策略可不可行,对于这道题而言,贪心的本质是让氪金的次数最少。所以当基友的第二个怪是0的时候,杀和不杀对于当前的氪金次数来说是没有影响的。但是对于后面的局面是会有影响的,并且可能会出现不同的结果。

比如我们可以找到一个例子10011,基友杀不杀第二个怪,直接影响后面的结果。如果基友杀了,那么不论“我”怎么选,基友都必须要至少再氪金一次。如果基友不杀,那么“我”杀第二个怪,基友再杀第三个怪,最后两个boss都交给“我”,那么基友全局只需要氪金一次。所以贪心算法不可行。

动态规划

如果你熟悉动态规划的话,那么几乎可以发现这是一道经典的动态规划问题。对于每一个怪来说,它都有两种状态,分别是被基友杀或者是被“我”杀。我们用0和1来分别表示,0表示被基友杀,1表示被“我”杀。一共有n个怪,所以我们可以用一个n * 2的数组来记录所有怪的状态。

对于第i个怪而言,如果它是被“我”杀的,那么它可以由基友杀了i-1或者是i-2个怪的状态转移得到。比如如果从基友杀了i-1转移得到,说明“我”杀了i,否则说明“我”不仅杀了i,还杀了i-1。同理i被基友杀的情况也是一样,所以这个状态转移方程就非常明显了。

# 学长的Python解法,注释满满
import sys t = int(input()) for _ in range(t):
n = int(input())
arr = list(map(int, input().split(' ')))
dp = [[sys.maxsize, sys.maxsize] for _ in range(n+2)] dp[0][1] = 0 for i in range(1, n+1):
if i > 1:
# 如果i > 1,那么说明可以杀两个
# 0表示基友杀怪的情况,基友可以杀1个从i-1转移得到,也可以杀2个从i-2转移得到
# 需要加上氪金的次数
dp[i][0] = min(dp[i-1][1] + arr[i-1], dp[i-2][1] + arr[i-2] + arr[i-1])
# 我杀怪不用氪金,直接赋值即可
dp[i][1] = min(dp[i-1][0], dp[i-2][0])
else:
# i=1,那么只能杀一个
dp[i][0] = dp[i-1][1] + arr[i-1]
dp[i][1] = dp[i-1][0] print(min(dp[n][0], dp[n][1]))
// 蒟蒻C++解法
// Author : RioTian
// Time : 20/11/07
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int main() {
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int x, ans = 0, sum = 0;
n--;
cin >> ans;
while (n--) {
cin >> x;
if (x)
sum++;
else
ans += sum / 3, sum = 0;
}
cout << ans + sum / 3 << endl;
}
}

最后,这道题非常的基础,可以说是动态规划的基础问题了。如果对动态规划这个概念不是很熟悉的话,非常建议动手做一做,加深一下印象。

Codeforce算法题 | 你能想出解法,让你的基友少氪金吗?的更多相关文章

  1. LeetCode算法题-First Bad Version(Java实现-三种解法)

    这是悦乐书的第200次更新,第210篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第66题(顺位题号是278).您是产品经理,目前领导团队开发新产品.不幸的是,您产品的最 ...

  2. LeetCode算法题-Longest Palindrome(五种解法)

    这是悦乐书的第220次更新,第232篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第87题(顺位题号是409).给定一个由小写或大写字母组成的字符串,找到可以用这些字母构 ...

  3. LeetCode算法题-Find the Difference(Java实现-五种解法)

    这是悦乐书的第214次更新,第227篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第82题(顺位题号是389).给定两个字符串s和t,它们只包含小写字母.字符串t由随机混 ...

  4. LeetCode算法题-Reverse Vowels of a String(Java实现-四种解法)

    这是悦乐书的第206次更新,第218篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第74题(顺位题号是345).编写一个函数,它将一个字符串作为输入,并仅反转一个字符串的 ...

  5. LeetCode算法题-Missing Number(Java实现-四种解法)

    这是悦乐书的第200次更新,第209篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第65题(顺位题号是268).给定一个包含n个不同数字的数组,取自0,1,2,...,n ...

  6. LeetCode算法题-Add Digits(Java实现-3种解法)

    这是悦乐书的第199次更新,第207篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第63题(顺位题号是258).给定非负整数num,重复添加其所有数字,直到结果只有一位数 ...

  7. LeetCode算法题-Minimum Distance Between BST Nodes(Java实现-四种解法)

    这是悦乐书的第314次更新,第335篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第183题(顺位题号是783).给定具有根节点值的二叉搜索树(BST),返回树中任何两个 ...

  8. LeetCode算法题-Number Complement(Java实现-五种解法)

    这是悦乐书的第240次更新,第253篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第107题(顺位题号是476).给定正整数,输出其补码数.补充策略是翻转其二进制表示的位 ...

  9. LeetCode算法题-Third Maximum Number(Java实现-四种解法)

    这是悦乐书的第222次更新,第235篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第89题(顺位题号是414).给定非空的整数数组,返回此数组中的第三个最大数字.如果不存 ...

随机推荐

  1. C 面向对象编程 --- 一模块的串口协议解析

    // 任务目的// 解析串口收到的54个字节.这54个字节包含了8个车道的5大信息以及校验信息.// 实现了查询每条车道包含了哪些信息. #include <stdio.h>#includ ...

  2. HTML中css水平居中的几种方式

    1. 子元素为行内元素时,父元素使用 text-align: center; 实现子元素的水平居中: 2. 子元素为块级元素时, 2.1. 将子元素设置 margin: 0 auto; 实现居中: 2 ...

  3. sysfs是什么??

    来源:https://blog.csdn.net/qq_36412526/article/details/83751520 第一次接触:sysfs, 这里记录过程: 原文:Documenttation ...

  4. 独立看第一个C++程序到最终结果log----2019-04-15

    本文纯为本人记录,有网上诸多参考,请勿转发! 记录可能可能有点啰嗦,自己划重点吧!! (无论是生活还是工作,如果很困惑,千万不要消极一定要勇敢积极的面对它,不用说太多懂得人自然懂,一定要解决这个疑惑就 ...

  5. Systemd的权威用法【译】

    如何使用journalctl 来观察和操作systemd的日志 介绍 systemd的一些不错的有点就是它能涉及到进程的系统的日志.对于其他日志工具,日志通常被分布到整个系统中,由不同的daemon和 ...

  6. Top Coder 某场Div 2的C题 题解

    前天,我们了解了一下一种叫做树状数组的神奇玩意儿,今天就放一道真题来检验一下自己的学习成果吧! 嗯,题目就是这样的啦. 分析: 这题的暴力大家应该都会打吧. 注意到m小的压批,所以对于每一个m值,我们 ...

  7. win10 home安装docker快速攻略

    本文适用于win10 Home用户,专业版和企业版直接见官网.win7版本见Docker Toolbox. 安装清单 软件 说明 Docker Desktop Installer 步骤介绍页:http ...

  8. MeteoInfoLab脚本示例:闪电位置图

    这个脚本示例读取文本格式的闪电数据,读出每条闪电记录的经纬度和强度,在地图上绘制出每个闪电的位置,并用符号和颜色区分强度正负.数据格式如下:0 2009-06-06 00:01:16.6195722 ...

  9. C++虚函数与多继承

    虚函数 C++用虚函数实现运行时多态,虚函数的实现是由两个部分组成的,虚函数指针与虚函数表. 虚函数指针(vptr)是指向虚函数表的指针,在一个被实例化的对象中,它总是被存放在该对象的地址首位.而虚函 ...

  10. lambda函数小结

    C++中的lambda函数 lambda函数是函数式编程中的概念,由C++11引入,成为现代C++中重要的特性. 所谓lambda函数就是匿名函数,语法结构: [capture list] (para ...