目录
这题是值得记录的一题,因为提交完发现时间效率和空间效率都比官方的高,对我来说这并不多见啊…有点小开心!
一、题目描述
Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇)
Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的一项:
- 禁止一名参议员的权利:参议员可以让另一位参议员在这一轮和随后的几轮中丧失所有的权利。
- 宣布胜利:如果参议员发现有权利投票的参议员都是同一个阵营的,他可以宣布胜利并决定在游戏中的有关变化。
给定一个字符串代表每个参议员的阵营。字母 “R” 和 “D” 分别代表了 Radiant(天辉)和 Dire(夜魇)。然后,如果有 n 个参议员,给定字符串的大小将是 n。
以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。
假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 Radiant 或 Dire。
示例 1:
输入:"RD"
输出:"Radiant"
解释:第一个参议员来自 Radiant 阵营并且他可以使用第一项权利让第二个参议员失去权力,因此第二个参议员将被跳过因为他没有任何权利。然后在第二轮的时候,第一个参议员可以宣布胜利,因为他是唯一一个有投票权的人
示例 2:
输入:"RDD"
输出:"Dire"
解释:
第一轮中,第一个来自 Radiant 阵营的参议员可以使用第一项权利禁止第二个参议员的权利
第二个来自 Dire 阵营的参议员会被跳过因为他的权利被禁止
第三个来自 Dire 阵营的参议员可以使用他的第一项权利禁止第一个参议员的权利
因此在第二轮只剩下第三个参议员拥有投票的权利,于是他可以宣布胜利
提示:
- 给定字符串的长度在 [1, 10,000] 之间.
二、解题思路
这题看题目应该是可以知道是贪心算法的,因为只有每一次让一位对手失去权力,才会更有可能赢。
这道题贪心的体现有两点:
- 每一位议员在行驶权力的时候都是先把后面的对手的权力禁止,这样对手就少了一名成员,直到后面没有对手了,才会去禁止前面的对手,而且是禁止最前面的对手,因为位置靠前是有一定优势的;
- 每一次的目标都是使自己赢的机会更大,这一点是从全局来看的贪心,上面步骤是从局部来看的最优。
局部最优的选择可以得到全局最优的选择,完全符合贪心算法。
三、代码实现
#include <bits/stdc++.h>
using namespace std;
string predictPartyVictory(string senate) {
//统计各阵营人数,people[0]代表R,people[1]代表D
vector<int> people(2, 0);
int length = senate.length();
for (int i = 0; i < length; i++) {
if (senate[i] == 'R') {
people[0]++;
} else
people[1]++;
}
//countR和countD分别代表阵营中被跳过的人数
int countR = 0, countD = 0;
//控制轮数,必须要进行到只剩一方的人为止
while (people[0] && people[1]) {
for (int i = 0; i < length; i++) {
if (senate[i] == 'R') {
if (countR) {
countR--;
//表示被移除了。这里不用删除字符,通过将他换成别的无关的字符来表示这个位置已被删除
senate[i] = 'N';
continue;
}
countD++;
if (--people[1] == 0) return "Radiant";
} else if (senate[i] == 'D') {
if (countD) {
countD--;
senate[i] = 'N';
continue;
}
countR++;
if (--people[0] == 0) return "Dire";
}
}
}
return people[0] ? "Radiant" : "Dire";
}
//官方题解
string predictPartyVictory2(string senate) {
int n = senate.size();
queue<int> radiant, dire;
for (int i = 0; i < n; ++i) {
if (senate[i] == 'R') {
radiant.push(i);
} else {
dire.push(i);
}
}
while (!radiant.empty() && !dire.empty()) {
if (radiant.front() < dire.front()) {
radiant.push(radiant.front() + n);
} else {
dire.push(dire.front() + n);
}
radiant.pop();
dire.pop();
}
return !radiant.empty() ? "Radiant" : "Dire";
}
int main() {
string senate = "RDD";
cout << predictPartyVictory(senate) << " ";
return 0;
}