灭鼠先锋
求解
本题是一道深度搜索+博弈论问题,当然之前没接触过博弈论也能用逻辑推导做。
首先解读题目,什么样的局面才能胜利。
可以发现,当下到只剩下一个圆圈的时候,我方一定胜。
那什么样的局面才会失败呢?就是对方让我方面对只剩下一个圆圈的情况。
从最终局面剩下一个圆圈的情况考虑,逐步想到最初的情况。使用深度优先搜索,遍历所有路径。如果只剩下一个圆圈时为必输局面,return False,则它的上一层必胜,return True,可以想到再上一层return还是False,下一层还是True,一直到最初的情况为止。由此可以写出dfs函数。
那怎么判定谁胜呢?
根据csdn其他题解,如
(2条消息) 2022年蓝桥杯省赛 C/C++ A组题解_蓝桥杯灭鼠先锋_傅志凌的博客-CSDN博客
,都默认当第一层dfs返回False时,先手胜利。但这种判定方式存在着反例:假设构造”OOOXXXXX“,返回的结果是错误的。
事实上,这个判断语句可以转化为,对于两行四列的所有特定的棋盘,如果先手胜,最优情况进行落子的操作次数一定是奇数,后手胜进行落子的操作次数一定是偶数。而事实并非如此,因此产生了矛盾。
归_溯的结论
这位佬给出了一些破解本题全面的结论。
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
//结论一,一行排满,下一行开头的必输
//结论二,剩余格子数为4时,此时有一对22分布格子或者没有,开头填1(这个1必须破坏22分布格子)的必赢
//结论三,剩余格子必须有两对22分布的格子,开头必输(由结论一和二得)
//结论四,剩余格子数为5时,如果有2对22分布格子,开头填1(这个1必须不能破坏2对22分布格子)的必赢(由结论三得)
//结论五,剩余格子数为5时,只有一对22分布的格子,开头填两个的必赢(由结论二得)
//结论六,剩余格子数为6时,如果有2对22分布格子,开头无论填什么都必输(由结论二,三,四,五得)
//结论七,剩余格子数为7时,如果有3对22分布格子,开头填两个格子的必输(由结论四和五得)
//总结,如果开头那个人填一个,第二步必须填一个(任意位置),结合以上所有结论,开头必输,
//若想先手赢,则一开始必须填两个,并且剩余6个格子符合结论六。
System.out.print("LLLV");
}
}
过样例的python代码:
def dfs(s):
# 当前为必输局势
if str(s).count("O")==1:
return False
# 放一个棋子
for i in range(len(s)):
if s[i]=='O':
temp=s
temp=list(temp)
temp[i]='X'
# 如果下一个局势可以是必输局势,当前局势必胜
if not dfs(temp):
return True
# 放两个棋子
for i in range(1,len(s)):
if s[i-1]=='O' and s[i]=='O' and i!=4:
temp=s
temp=list(temp)
temp[i-1]='X'
temp[i]='X'
if not dfs(temp):
return True
# 如果下一个局势是必胜局势,当前局势必输
return False
st=['XOOOOOOO','XXOOOOOO' ,'OXOOOOOO' ,'OXXOOOOO']
for i in range(len(st)):
print('V',end='') if not dfs(st[i]) else print('L',end='')
print(dfs(st[i]))
# 如果dfs返回False,则先手胜。
小蓝与钥匙
求解
有两个解法。
第一个解法,不仅必须知道第一类斯特林数s(n,k),表示将 n 个两两不同的元素,划分为 k 个互不区分的非空轮换的方案数的概念,而且因为它没有通项公式,所以还要知道将14个两两不同的元素,划分为14个非空轮换时的s,把它乘C28取14就是结果。
上网址中有计算递推式,可用程序算。
第二个解法,根据实际意义算s(14,14),也就是假设这14个孩子都拿到自己房间的钥匙,然后互相交换,求有多少种交换方法。所以用dfs求全排列+剪枝,时间复杂度O((n-1)!)。
a=[i for i in range(14)]
b=[0]*14
vis=[False]*14
cnt=0
def dfs(s,t):
global cnt
if cnt>1286583532342313400:
print("wrong")
# 统计有效方案数
if s==t:
cnt+=1
else:
for i in range(t):
if s==a[i]:
continue
if vis[i]==False:
vis[i]=True
b[s]=a[i]
dfs(s+1,t)
vis[i]=False
dfs(0,14)
print(cnt)
占个坑
浙公网安备 33010602011771号