【数据结构与算法】之深入解析“石子游戏VI”的求解思路与算法示例
【摘要】
一、题目要求
Alice 和 Bob 轮流玩一个游戏,Alice 先手,一堆石子里总共有 n 个石子,轮到某个玩家时,他可以移出一个石子并得到这个石子的价值。Alice 和 Bob 对石子价值有不一样的...
一、题目要求
- 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;
}
};
文章来源: blog.csdn.net,作者:Serendipity·y,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/Forever_wj/article/details/122273218
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)