算法笔记:国王游戏

这篇具有很好参考价值的文章主要介绍了算法笔记:国王游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目来源:thttps://oj.haizeix.com/problem/256
题目描述

​ 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

​ 国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。


输入

​ 第一行包含一个整数 n,表示大臣的人数。

​ 第二行包含两个整数 a 和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。(均小于 1000010000)

​ 接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。(均小于 1000010000)

输出

​ 输出一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。


样例输入
3
1 1
2 3
7 4
4 6
样例输出
2

数据规模与约定

​ 时间限制:1 s

​ 内存限制:256 M

​ 100% 的数据保证 1≤n≤1000

解决这道题所需的一个算法思想叫“微扰”。所谓微扰,就是微微地干扰一下。我们先来对题目进行分析:

1.首先我们有一个初始的大臣(可简化为一个二元组)序列,每一个二元组都有一个与其相对应的值(也就是每一个大臣可获得的金币数量)。我们分别用L和R来代表左手上的数字和右手上的数字,i来代表第几个大臣。例如Li就是第i个大臣的左手数字。设大臣获得金币数量为C,那么我们可以得出每一个大臣可以获得的金币数量公式为:                           

                                                       

2.接下来我们开始微扰:假设我们已经知道获得金币最多的大臣时第i+1个,获得的金币数为C(i+1),我们可以调换一下他与他前面的那个大臣,也就是第i位大臣的位置。之后我们可以对比调换前后的两个序列的金币最大值,而我们所希望的是:调换之后的序列的金币最大值要小于调换前的,这样就代表着我们至少走对了一步。

算法笔记:国王游戏,算法,笔记,c++
上面是调换前,下面是调换后

值得说明的是,我们不难(?)发现,我们调换位置后,只有被调换的两个C值会发生变化,其他的C值都照常不变。

3.那么要想走对这一步,代价是什么呢?我的意思是,我们需要Ci和C(i+1)满足什么样的条件呢?我们无需知道具体是哪一个C成为了调换后序列的最大值,我们只需要知道,调换后的最大值确实变小了。不难看出, 除了被调换的这两项,其余的C都是要小于我们的C(i+1)的,那么我们只需要证明被调换后,值被改变的Ci和C(i+1)的值都小于调换前的C(i+1)即可。

我们代入公式:

                                                      

                                              算法笔记:国王游戏,算法,笔记,c++

                                               算法笔记:国王游戏,算法,笔记,c++

                                                  算法笔记:国王游戏,算法,笔记,c++

我们不难发现,调换后的C(i+1)肯定小于原本的C(i+1),那么我们只需比较C(i+1)与调换后的Ci即可,将公式化简得:

                                                    算法笔记:国王游戏,算法,笔记,c++

达成这个条件,我们就可以知道,调换后的最大值小于调换前的最大值。我们可以把这个公式推广一下:对于任意两个相邻的大臣,只要他们满足以上公式,那么他们在调换位置之后,至少在他们二人中,最大值会变得更小。继续把这个公式推广至所有大臣:如果对于每一对相邻的大臣而言都不在满足这个条件,那么是不是就可以说明,不会再出现更小的最大值了呢?这其实就相当于以这个公式为我们的排序条件,对所有大臣进行排序,就可以解决这道题。

代码如下:

//256. 国王游戏
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main()
{
	int n;
	cin >> n;
	vector<pair<long long, long long>> v;
	for (int i = 0; i <= n; i++)
	{
		pair<long long, long long> p;
		cin >> p.first;//first和second分别代表左手和右手
		cin >> p.second;
		v.push_back(p);
	}
	sort(v.begin() + 1, v.end(), [&](pair<long long, long long> a, pair<long long, long long> b) ->bool
		{
			return a.first * a.second < b.first * b.second;
		});
	long long total = v[0].first;
	long long Max = 0;
	for (int i = 1; i < v.size(); i++)
	{
		Max = max(Max, total / v[i].second);
		total *= v[i].first;
	}
	cout << Max;
}

但我们把这份代码提交上去后,却只有60分,这么绘事呢?观察未通过的四个检查点我们可以发现,其要求的答案都是非常大的数,超过了2的32次方,甚至超过了long long的表示范围,这说明,虽然咱们的思路是对的,算法也没有问题,但普通的代码实现并不能完全解决这道题。我们还需要实现一个大整数类。这可能需要重构之前的部分代码。文章来源地址https://www.toymoban.com/news/detail-812781.html

//256. 国王游戏
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

#define MAX_N 1000
int a[MAX_N + 5], b[MAX_N + 5], ind[MAX_N + 5];

class BigInt : public vector<int> { // 1234 -> [4, 3, 2, 1]
public :
    BigInt(int x) {
        this->push_back(x);
        proccess_digit();
        return ;
    }
    BigInt operator/(int x) {
        BigInt ret(*this);
        int y = 0;
        for (int i = size() - 1; i >= 0; i--) {
            y = y * 10 + at(i);
            ret[i] = y / x;
            y %= x;
        }
        ret.proccess_digit();
        return ret;
    }
    void operator*=(int x) {
        for (int i = 0; i < size(); i++) at(i) *= x;
        proccess_digit();
        return ;
    }
    bool operator>(const BigInt &a) const {
        if (size() != a.size()) return size() > a.size();
        for (int i = size() - 1; i >= 0; i--) {
            if (at(i) != a[i]) return at(i) > a[i];
        }
        return false;
    }
    void proccess_digit() {
        for (int i = 0; i < size(); i++) {
            if (at(i) < 10) continue;
            if (i + 1 == size()) this->push_back(0);
            at(i + 1) += at(i) / 10;
            at(i) %= 10;
        }
        while (size() > 1 && at(size() - 1) == 0) this->pop_back();
        return ;
    }
};

ostream &operator<<(ostream &out, const BigInt &a) {
    for (int i = a.size() - 1; i >= 0; i--) {
        out << a[i];
    }
    return out;
}

int main() {
    int n;
    cin >> n;
    for (int i = 0; i <= n; i++) {
        cin >> a[i] >> b[i];
        ind[i] = i;
    }
    sort(ind + 1, ind + n + 1, [&](int i, int j) -> bool {
        return a[i] * b[i] < a[j] * b[j];
    });
    BigInt p = a[0], ans = 0, temp = 0;
    for (int i = 1; i <= n; i++) {
        temp = p / b[ind[i]];
        if (temp > ans) ans = temp;
        p *= a[ind[i]];
    }
    cout << ans << endl;
    return 0;
}

到了这里,关于算法笔记:国王游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CSC改派+延期|影像学医生赴英国伦敦国王学院从事访学研究

    因美国拒签,又临近派出截止期限。为避免出国指标作废,Q医生希望获得英国高校的邀请函,以申请CSC的改派并延期。我们为其落实了世界名校-英国伦敦国王学院访问学者职位,导师的研究方向属前沿热点,具有广阔的发展前景。Q医生非常满意,最终顺利过签出国。 Q 医生

    2024年02月09日
    浏览(29)
  • 【算法刷题 | 贪心算法04】4.26(跳跃游戏、跳跃游戏||)

    给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例一: 示例二: 6.2.1贪心思路 一般思路:当前位置元素如果是 3,我究竟

    2024年04月27日
    浏览(29)
  • 【结构与算法】—— 游戏概率常用算法整理 | 游戏中的常见概率设计分析

    📢博客主页:肩匣与橘 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 肩匣与橘 编写,首发于 CSDN 🙉 📢生活依旧是美好而又温柔的,你也是✨  目录 一、随机数生成 二、概率分布 2.1均匀分布 2.2正态分布 2.3泊松分布 三、随机事件触发 3.1固定概率触发

    2024年02月05日
    浏览(30)
  • DAY37:贪心算法(四)跳跃游戏+跳跃游戏Ⅱ

    给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 示例 1: 示例 2: 提示: 1 = nums.length = 3 * 104 0 = nums[i] = 105 思路 游戏大致规则如下图。每一步代表着能跳跃的最大长

    2024年02月12日
    浏览(35)
  • Games104现代游戏引擎笔记 网络游戏进阶架构

    玩家2的视角看玩家1的移动是起伏一截一截,并且滞后的 interpolation:内插值,在两个旧的但已知的状态计算 extrapolation:外插值,本质是预测 内插值:但网络随着时间不停地给我信息包时,信息包可以不均匀(由于网络波动等因素),客户端可以根据给的时间将中间值插出来

    2024年02月08日
    浏览(32)
  • Games104现代游戏引擎笔记 网络游戏架构基础

    挑战1:网络同步 挑战2:是网络的可靠性,包括应对网络的延迟,丢包和掉线 挑战3: 反作弊和安全系统,因为网络游戏的本质是经济系统 挑战4:多样性(不同设备,不同服务器),在不停服的情况下热更新 挑战5:大量人数时对高并发,高操作的要求 Socket编程,通过接口,确认好相

    2024年02月08日
    浏览(46)
  • 跳跃游戏【贪心算法】

    跳跃游戏 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。在这里插入图片描述

    2024年02月11日
    浏览(31)
  • 贪心算法-01:跳跃游戏

    贪心算法是动态规划的一个特例,相对于动态规划,使用贪心算法需要满足更多条件,但是效率比动态规划要高。 贪心选择的性质就是:每一步都做出一个局部最优解,最终的结果就是全局最优。不过这是一种特殊性质,只有一部分问题拥有这个性质。 比如面前放有100张人

    2024年01月22日
    浏览(33)
  • 贪心算法-跳跃游戏

    给你一个非负整数数组  nums  ,你最初位于数组的  第一个下标  。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回  true  ;否则,返回  false  。 示例 1: 示例 2: 提示: 1 = nums.length = 104 0 = nums[i] = 105 贪心在

    2024年04月27日
    浏览(25)
  • unity学习笔记----游戏练习06

    一、豌豆射手的子弹控制 创建脚本单独控制子弹的运动 用transform来控制移动     void Update()     {         transform.Translate(Vector3.right * speed * Time.deltaTime);     } 创建一个控制子弹速度的方法,方便速度的控制 private void SetSpeed(float speet)     {         this.speed = speet;     } 回到

    2024年01月25日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包