数据结构与算法之深入解析“石子游戏VI”的求解思路与算法示例
Posted Forever_wj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法之深入解析“石子游戏VI”的求解思路与算法示例相关的知识,希望对你有一定的参考价值。
一、题目要求
- Alice 和 Bob 轮流玩一个游戏,Alice 先手,一堆石子里总共有 n 个石子,轮到某个玩家时,他可以移出一个石子并得到这个石子的价值。Alice 和 Bob 对石子价值有不一样的的评判标准,双方都知道对方的评判标准。
- 给你两个长度为 n 的整数数组 aliceValues 和 bobValues,aliceValues[i] 和 bobValues[i] 分别表示 Alice 和 Bob 认为第 i 个石子的价值。
- 所有石子都被取完后,得分较高的人为胜者,如果两个玩家得分相同,那么为平局,两位玩家都会采用 最优策略 进行游戏。
- 请你推断游戏的结果,用如下的方式表示:
-
- 如果 Alice 赢,返回 1;
-
- 如果 Bob 赢,返回 -1;
-
- 如果游戏平局,返回 0。
- 示例 1:
输入:aliceValues = [1,3], bobValues = [2,1]
输出:1
解释:
如果 Alice 拿石子 1 (下标从 0开始),那么 Alice 可以得到 3 分。
Bob 只能选择石子 0 ,得到 2 分。
Alice 获胜。
- 示例 2:
输入:aliceValues = [1,2], bobValues = [3,1]
输出:0
解释:
Alice 拿石子 0 , Bob 拿石子 1 ,他们得分都为 1 分。
打平。
- 示例 3:
输入:aliceValues = [2,4,3], bobValues = [1,6,7]
输出:-1
解释:
不管 Alice 怎么操作,Bob 都可以得到比 Alice 更高的得分。
比方说,Alice 拿石子 1 ,Bob 拿石子 2 , Alice 拿石子 0 ,Alice 会得到 6 分而 Bob 得分为 7 分。
Bob 会获胜。
二、求解算法
① 贪心算法
- 假设只有两个石头,对于 a, b 的价值分别是 a1,a2,b1,b2:
-
- 第一种方案是 A 取第一个,B 取第二个,A 与 B 的价值差是 c1 = a1 - b2;
-
- 第二种方案是 A 取第二个,B 取第一个,A 与 B 的价值差是 c2 = a2 - b1;
- 那么这两种方案对于 A 来说哪一种更优,就取决于两个方案的价值差的比较。
- 记 c = c1 - c2 = (a1 - b2) - (a2 - b1) = (a1 + b1) - (a2 + b2),如果 c > 0 那么方案一更优,如果 c == 0,那么两种方案价值一样,如果 c < 0 ,那么方案二更优。
- 比较两个方案的优劣就如同比较 a1 + b1 与 a2 + b2 的优劣,归纳一下就是比较每个下标 i 的 a[i] + b[i] 的优劣,所以贪心的策略:将两组石头的价值合并,每次取价值最大的那一组。
- 合并 aliceValues 与 bobValues 的数组,按最大价值从大到小排列,Alice 先选,Bob 后选,偶数下标就标称 Alice 选取的石头的总价值,Bob 选的则是奇数下标的石子,比较两个总和。
- C++ 示例:
class Solution
public:
int stoneGameVI(vector<int>& aliceValues, vector<int>& bobValues)
vector<pair<int, int>> mp; // 记录价值和以及下标
int n = aliceValues.size();
for(int i = 0; i < n; i++)
int dis = aliceValues[i] + bobValues[i];
mp.emplace_back(dis, i);
sort(mp.rbegin(), mp.rend()); // 从大到小排序
int sum1 = 0, sum2 = 0;
for(int i = 0; i < n; i++)
if(i % 2 == 0) sum1 += aliceValues[mp[i].second];// 偶数下标a来取
else sum2 += bobValues[mp[i].second]; // 奇数下标b来取
if(sum1 == sum2) return 0; // 比较结果
else if(sum1 > sum2) return 1;
else return -1;
;
② 数学推理
- 双赢才是赢,不仅 Alice 要认为某块石头的价值大,Bob 也要认为的时候,才是真的大。
- 因此,将某块石头在 Alice 眼中的价值 +Bob 眼里的价值相加,排序,然后 Alice 和 Bob 依次进行挑选,最比较 Alice 和 Bob 的得分。
- C++ 示例:
class Solution
public:
int stoneGameVI(vector<int>& aliceValues, vector<int>& bobValues)
vector<pair<int,int>>vc;
int len=aliceValues.size();
for(int i=0;i<len;i++)
// 合并石头的双从的价值
int sum=aliceValues[i]+bobValues[i];
vc.push_back(sum,i);
// 对合并后的石头的价值进行排序
sort(vc.rbegin(),vc.rend());
// Alice的得分
int A=0;
// Bob的得分
int B=0;
for(int i=0;i<len;i++)
// 依次轮流拿去石头
if(i%2==0)
A+=aliceValues[vc[i].second];
else
B+=bobValues[vc[i].second];
// 返回最后的结果
if(A==B)
return 0;
return A>B?1:-1;
;
三、博客之星
- 今年是我第一次参加博客之星,需要各位大佬的支持,麻烦百忙之中,抽出一点宝贵的时间,给我投一下票:https://bbs.csdn.net/topics/603955258 给我一个五星(列表会一一全部回复),不胜感激!
以上是关于数据结构与算法之深入解析“石子游戏VI”的求解思路与算法示例的主要内容,如果未能解决你的问题,请参考以下文章
数据结构与算法之深入解析“股票的最大利润”的求解思路与算法示例