Alice和Bob玩下面的游戏:
1)他们选择开头的前N个数字的排列。
2)他们交替上场,而爱丽丝则先上场。
3)在一个回合中,他们可以从排列中删除任何剩余的数字。
4)当剩余数字形成递增序列时,游戏结束。最后一个回合(在序列变得增加之后)的人赢得比赛。
假设两者都以最佳方式进行比赛,谁赢了比赛?
输入: 第一行包含测试用例的数量T.T测试用例如下。每个案例在第一行包含一个整数N,然后在第二行包含整数1..N的排列。
输出: 输出T行,每个测试用例一行,如果Alice赢了游戏则包含“Alice”,否则包含“Bob”。
示例输入:
2
3
1 3 2
5
5 3 2 1 4
示例输出:
爱丽丝
鲍勃
约束:
1 <= T <= 100
2 <= N <= 15
最初的排列不会是一个增加的序列。
我正在努力解决上述问题。我已经衍生到很远,但我陷入了困境。请帮我进一步。
在上述问题中,对于长度为2的排列,玩家1总是获胜。
对于长度为3的排列,如果字符串严格增加或减少,则播放器2获胜。
对于长度为4的排列,如果玩家1能够通过删除一个角色使字符串严格增加或减少,则她赢得其他玩家2胜。
因此得出结论:
如果当前玩家能够使字符串严格增加他/她获胜。 (琐碎案例)
如果他/她能够严格减少,则获胜者由该序列中的元素数决定。如果该序列中有偶数个元素,则当前玩家将失败,否则获胜。
但是,如果结果字符串既不增加也不减少,应该怎么做?
答案 0 :(得分:9)
这是一个典型的游戏问题。您有2 ^ 15个可能的位置,表示剩余的数字。根据剩余数字的数量,你可以得出轮到它的数量。所以现在你有一个以下面的方式定义的图形 - 顶点是剩余数字的可能集合,并且有一条边连接两个顶点u和v iff有一个移动改变set u to set v(即set v只有一个数字。)
现在你已经指出了哪些位置你知道谁是胜利者 - 那些代表不断增加的数字序列的位置被标记为失败。对于所有其他位置,您可以通过以下方式确定它们是否正在获胜或失去:如果有一个边缘将其连接到松动位置,则获胜。所以剩下的就是像带有记忆的dfs那样你可以确定哪些位置正在赢,哪些位置正在消失。由于图形相对较小(2 ^ 15个顶点),因此该解决方案应该足够快。
希望这有帮助。
答案 1 :(得分:4)
当然,对于小N来说,这可以用“蛮力”来完成,但是你不怀疑inversions和the sign of a permutation周围的答案是否更容易?
最初我怀疑有一个答案,如果“如果标志是-1,则会失败,否则会失败”,但事实并非如此。
但我想提出一个问题的表示,不仅是你的算法可能会使用,而且会在这个游戏中同样提高你的纸笔性能。
反转是一对索引i&lt; j,使得a [i]> a [j]。考虑(i
,j
)具有顶点1,...,N的无向图的边。每个玩家从该图中删除一个顶点,如果没有边缘则获胜。
对于5 3 2 1 4
,结果图是
5--3
/|\ |
/ | \|
4 1--2
并且Alice很快发现删除“5”会让Bob有机会删除2.然后没有留下任何反转,Bob就赢了。
答案 2 :(得分:2)
这个游戏可以递归解决。
每次alice采取她的第一个选择并选择i,从所有剩余的大于i的数字中减去1。现在我们有相同的游戏,但数字1到N-1
假设你的序列是
1,3,5,4,2
在她的第一步中,爱丽丝可以选择任何号码。 情况1: 她选择1,如果鲍勃不能以3,5,4,2(相当于2,4,3,1)获胜,爱丽丝可以获胜情况2: 她先选了3个。如果鲍勃不能赢得1,5,4,2(相当于1,4,3,2)
,爱丽丝可以获胜情形3: 她先挑了5个。如果鲍勃不能赢得1,3,4,2
,爱丽丝可以获胜你明白了。
因此,您可以通过对每个可能的第一个猜测使用大小N-1个排列来制作递归函数来计算出大小为N的排列。递归的基本情况是当你有一个有序序列时。
递归的每一步,人都会尝试所有可能性,并挑选任何能让他们获胜的人。
因为有许多移动组合可以归结为相同的序列,所以递归具有重叠的子问题。这意味着我们可以使用动态编程,或者简单地“记忆”我们的功能,从而大大提高效率。
为了进一步加速,可以在排列中使用对称性,因为许多排列组是等价的,例如一个排列的反转将产生相同的结果。
祝你好运。答案 3 :(得分:1)
@ tiwo,@ rup COnsidering 5 3 2 1 4是序列第一个alice删除5并且bob删除2然后序列是3 1 4,这不是递增顺序然后alice有机会删除1和序列按升序排列,Alice应该是答案。在你给出的图表中,应该有一个介于3和1之间的边,因为1和3是反转的。
请告诉我我错在哪里,因为问题中给出的答案实际上是BOB
答案 4 :(得分:1)
您可以使用minimax算法解决它。这是java中的代码
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
int t = ni();
for(int i=0; i<t; i++){
int n = ni();
Map<Long, Boolean> map = new HashMap<Long, Boolean>();
int[] numbers = new int[n];
for(int j=0; j<n; j++){
numbers[j] = ni();
}
if(aliceWin(numbers, map)) System.out.println("Alice");
else System.out.println("Bob");
}
}
public static boolean aliceWin(int[] a, Map<Long, Boolean> map){
long h = hashCode(a); int temp;
if(map.containsKey(h)) return true;
for(int i=0; i<a.length; i++){
if(a[i]>0){
temp = a[i] ;
a[i] = 0;
if(isIncreasing(a)){
map.put(h, true);
a[i] = temp;
return true;
}
if(!aliceWin(a, map)) {
map.put(h, true);
a[i] = temp;
return true;
}
a[i] = temp;
}
}
return false;
}
public static long hashCode(int[] a){
long result = 0;
for(int i=0; i<a.length; i++){
result = (result << 4) + a[i];
}
return result;
}
public static boolean isIncreasing(int[] a){
int last = 0;
for(int i=0; i<a.length; i++){
if (a[i] > 0){
if(last > a[i]) return false;
last = a[i];
}
}
return true;
}
public static int ni(){
return sc.nextInt();
}
public static void print(Object... args){
System.out.println(Arrays.deepToString(args));
}
}
答案 5 :(得分:0)
以下是一些为您构建图形的代码,但要求您在图形上调用reverse(),创建连接到基础中所有节点的源节点,返回源代码,看看是否有alice获胜的方式
input_ = """2
3
1 3 2
5
5 3 2 1 4""".splitlines()
perms = [map(int,perm.split()) for perm in input_ if len(perm)>1]
"[['1', '3', '2'], ['5', '3', '2', '1', '4']]"
if networkx is None:
import networkx
from itertools import combinations
def build_graph(perm):
base = set()
G = networkx.DiGraph()
for r in range(1,len(perm)+1):
for combo in combinations(perm,r):
combo = list(combo)
if combo == sorted(combo):
base.add(tuple(combo))
continue
for i in range(r):
G.add_edge(tuple(combo),tuple(combo[:i]+combo[i+1:])) #you may want to reverse the graph later to point from base to source.
return G,base
def solve(G,base):
#dfs,
pass
for perm in perms:
G,base = build_graph(perms[0])
print solve(G,base)
答案 6 :(得分:-1)
我们不能只检查每一步...... 由下一个玩家进行的单一更改会使序列排序..如果是,则进行其他移动.. 或继续搬家
像 5 3 2 1 4 如果爱丽丝做3 2 1 4 通过消除任何...,鲍勃不能一蹴而就 好像 他做了2 1 4它是排序的.. 他做了3 1 4它是排序的.. 他做了3 2 4它是排序的.. 所以5 3 2 1 4 - &gt; 3 2 1 4是有效的举动!!
现在轮到了... 他会检查一下.. 但是在某个时候......不会有一个这样的数字,你可以像上面那样采取行动。 所以你必须做一个随机的动作然后谁会赢,然后可以很容易地通过将序列变成单个元素的步数来计算!!
答案 7 :(得分:-2)
给我(几乎用你自己的话):
如果他/她能够在第一步中严格增加他/她获胜(琐事),否则获胜者将由该序列中的元素数决定。
以你的第二个案例为例。
我认为图表解决方案很好,但它会忘记玩家以最佳方式玩游戏。因此,不需要检查所有不同的路径,因为其中一些路径将来自非最佳选择。