题目:
Dota2 的世界里有两个阵营:Radiant
(天辉)和 Dire
(夜魇)
Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的 一 项:
- 禁止一名参议员的权利:参议员可以让另一位参议员在这一轮和随后的几轮中丧失 所有的权利 。
- 宣布胜利:如果参议员发现有权利投票的参议员都是 同一个阵营的 ,他可以宣布胜利并决定在游戏中的有关变化。
给你一个字符串 senate
代表每个参议员的阵营。字母 'R'
和 'D'
分别代表了 Radiant
(天辉)和 Dire
(夜魇)。然后,如果有 n
个参议员,给定字符串的大小将是 n
。
以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。
假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 "Radiant"
或 "Dire"
。
示例输出:
示例 1:
输入:senate = "RD" 输出:"Radiant" 解释:第 1 轮时,第一个参议员来自 Radiant 阵营,他可以使用第一项权利让第二个参议员失去所有权利。 这一轮中,第二个参议员将会被跳过,因为他的权利被禁止了。 第 2 轮时,第一个参议员可以宣布胜利,因为他是唯一一个有投票权的人
。示例 2:
输入:senate = "RDD" 输出:"Dire" 解释: 第 1 轮时,第一个来自 Radiant 阵营的
参议员可以使用第一项权利禁止第二个参议员的权利。这一轮中,
第二个来自 Dire 阵营的
参议员会将被跳过,因为他的权利被禁止了。这一轮中,
第三个来自 Dire 阵营的
参议员可以使用他的第一项权利禁止第一个参议员的权利。 因此在第二轮只剩下第三个参议员拥有投票的权利,于是他可以宣布胜利
题目分析:
这道题 题意太绕了,我举一个更形象的例子给大家捋顺一下。
例如输入"RRDDD",执行过程应该是什么样呢?
- 第一轮:senate[0]的R消灭senate[2]的D,senate[1]的R消灭senate[3]的D,senate[4]的D消灭senate[0]的R,此时剩下"RD",第一轮结束!
- 第二轮:senate[0]的R消灭senate[1]的D,第二轮结束
- 第三轮:只有R了,R胜利
估计不少同学都困惑,R和D数量相同怎么办,究竟谁赢,其实这是一个持续消灭的过程! 即:如果同时存在R和D就继续进行下一轮消灭,轮数直到只剩下R或者D为止!
那么每一轮消灭的策略应该是什么呢?
例如:RDDRD
第一轮:senate[0]的R消灭senate[1]的D,那么senate[2]的D,是消灭senate[0]的R还是消灭senate[3]的R呢?
当然是消灭senate[3]的R,因为当轮到这个R的时候,它可以消灭senate[4]的D。
所以消灭的策略是,尽量消灭自己后面的对手,因为前面的对手已经使用过权利了,而后序的对手依然可以使用权利消灭自己的同伴!
那么局部最优:有一次权利机会,就消灭自己后面的对手。全局最优:为自己的阵营赢取最大利益。
局部最优可以推出全局最优,举不出反例,那么试试贪心。
思路:
这个问题的解决思路如下:
. 首先,我们将参议员按照所属阵营分成两个队列:一个队列用于存储天辉参议员(Radiant),另一个队列用于存储夜魇参议员(Dire)。
然后,我们模拟每一轮的投票过程,直到有一个阵营的参议员宣布胜利。每一轮投票中,我们从两个队列中分别取出一个参议员,分别代表天辉和夜魇,然后判断哪个参议员会禁止另一个参议员的权利。
如果天辉参议员的索引小于夜魇参议员的索引,那么天辉参议员会禁止夜魇参议员的权利,并将自己放回队列以参与下一轮投票。否则,夜魇参议员会禁止天辉参议员的权利,并将自己放回队列。
重复这个过程,直到有一个阵营的参议员被全部禁止权利,那个阵营的参议员宣布胜利。
最后,返回获胜阵营的名称,即天辉(Radiant)或夜魇(Dire)。
这个算法保证了每个参议员都会选择最优策略,即禁止能够投票的对方阵营的参议员,直到有一个阵营的参议员胜利为止。
代码实现:
import java.util.LinkedList;
import java.util.Queue;
public class SenateSimulation {
public String predictPartyVictory(String senate) {
int n = senate.length();
Queue<Integer> radiant = new LinkedList<>();
Queue<Integer> dire = new LinkedList<>();
// 将天辉和夜魇的参议员分别放入对应的队列
for (int i = 0; i < n; i++) {
char senator = senate.charAt(i);
if (senator == 'R') {
radiant.offer(i);
} else {
dire.offer(i);
}
}
while (!radiant.isEmpty() && !dire.isEmpty()) {
int r = radiant.poll();
int d = dire.poll();
// 判断哪个参议员会禁止另一个参议员的权利
if (r < d) {
radiant.offer(r + n); // 天辉参议员将在下一轮
} else {
dire.offer(d + n); // 夜魇参议员将在下一轮
}
}
return radiant.isEmpty() ? "Dire" : "Radiant";
}
public static void main(String[] args) {
SenateSimulation solution = new SenateSimulation();
String senate = "RD";
String winner = solution.predictPartyVictory(senate);
System.out.println("The winner is: " + winner); // 输出 "Radiant"
}
}