1,A,B玩家取纸牌牌,看获胜者分数的问题
2,村里的人相互收发信的方案数
3,N皇后问题的方案数
1,A,B玩家取纸牌牌,看获胜者分数的问题
给定一个整型数组arr,代表数值不同的纸牌排成一条线,玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但是每个玩家每次只能拿走最左或者最右的纸牌,玩家A和玩家B都决定聪明。请返回最后获胜者的分数。
思路:
创建两个子函数,分别是在当前arr中,作为先手拿到的牌值和作为后手拿到的牌值,L和R指示当前纸牌左右的索引。作为先手的人有两个选择,一个选择拿左边,然后递归调用L+1到R中作为后手的最大纸牌值,一个是选择拿右边,然后递归调用L到R-1作为后手的最大纸牌值,这两个选择的纸牌值取最大数。作为后手的人在当前的arr中,只能被动的选择当前的先手在L+1到R中的,以及先手在当前的L到R-1中返回的最小值。
伪代码流程
fun_first(arr, L, R):
if L==R:
return arr[L]
return max(arr[L] + fun_second(arr, L+1,R), arr[R]+ fun_second(arr, L, R-1))
fun_second(arr, L, R)
if L==R:
return 0;
return min(fun_first(arr, L+1,R), fun_first(arr, L, R-1))
fun_main(arr):
if arr==null || arr.length ==0:
return 0
return max(fun_first(arr, 0, arr.length-1), fun_second(arr, 0, arr.length-1))
2,村里的人相互收发信的方案数
一个村庄有n个人,每个人规定必须完成这个任务:给别人发一封信,并且收到一封信,请问完成任务可以有多少种方法?
思路
当n=1时候,有0种方法。
当n=2时候,有1种方法。即A发给B,B发给A
当n=3时候,有2种方法。即A发给B,B发给C,C发给A;A发给C,C发给B,B发给A
当n =5时候,假设是A,B,C,D,E 五个人,
A可以发给B,C,D,E任意一个人,假设分给了B,那么接下来分为两种情况,一是B发信给了A,此时还有n=3的方法数情况;二是B没有发信给A,那么接下来A需要收到一封信,B需要发出一封信,就等效于AB为一个新人,和C,D,E共同组成一个n=4的村庄的情况下方法数。
所以递归方法数为(n-1)* (f(n-1)+f(n-2))。
3,N皇后问题
在一个N * N的棋格上,任意行,任意斜线上只能有一个皇后数,求组成N皇后的棋盘摆放方案数。
思路
用 i 表示当前要摆放第几行,数组record有N个数,record[i]表示第i行的皇后放在了第几列,ans表示方案数。逐行确定第 i 行皇后可摆放位置,如果有多个,按顺序遍历。如果后面发现其它行没有可摆放的位置,表示当前行摆放位置不可取,回溯至此,遍历下一个摆放位置。
伪代码流程:
fun_process(N, i, record):
if i==N:
return 1
ans =0
for j in range(N-1):
if fun_isValid(record, i, j):
record[i]= j
ans +=fun_process(N, i+1, record)
return ans
fun_isValid(record, i, j)://判断放在i,j位置会不会和i之前的行冲突
for k in range(i):
if (record[k] == j) or abs(i-k)==abs(record[k]-j):
return False
return True
fun_main(N):
if N==1:
return 0
record=[0].zfill(N) //N 个0的数组
ans =fun_process(N, 0, record)
return ans
N 皇后问题的时间复杂度都是N**2,但是可以通过位运算,优化常数项的时间。
用limit是一个N位的数值,每个bit位置都是1表示最终要解决N行个皇后,列的限制用colLim也是一个N位的数,每位都用0,1表示,当bit=1表示该列受限,皇后不能放在这列了,leftDiaLim和rightDiaLim分别表示左斜线和右斜线的限制。当在colLim的某个bit放了皇后后,leftDiaLim是该(leftDiaLim | mostRightOne)<<1,mostRightOne表示colLim可放皇后的最右边那个bit位置。
两种方法的python代码如下,明显process2更快
# -*- coding: utf-8 -*-
import numpy as np
import time
def isValid(record,i,j):
for k in range(i):
if record[k]==j or abs(record[k]-j)==abs(i-k):
return False
return True
def process1(N,i, record):
if i==N:
return 1
ans =0
for j in range(N):
if isValid(record, i,j):
record[i]=j
ans+=process1(N, i+1,record)
return ans
def process2(limit, colLim, leftDiaLim, rightDiaLim):
if (colLim ==limit):#所有位都排好了
return 1
#所有候选位置的皇后位置都在pos上
pos =limit & (~(colLim | leftDiaLim | rightDiaLim))
ans =0
while(pos !=0):
mostRightOne = pos & (~pos +1) #可放皇后的最右边的列位置
pos =pos -mostRightOne
ans+=process2(limit,colLim | mostRightOne,(leftDiaLim | mostRightOne)<<1,(rightDiaLim | mostRightOne)>>1)
return ans
if __name__ =='__main__':
N=9
if N==1 :
print('ans is :',0)
else:
record=np.zeros(N)
t1=time.time()
ans =process1(N,0,record)
print ('process1 ans is %d,cost time is %f'%(ans, time.time()-t1))
if N >32:
print('not support')
limit=-1 if N==32 else (1<<N)-1
t2=time.time()
ans2=process2(limit,0,0,0)
print('process2 ans is %d, cost time is %f'%(ans2,time.time()-t2))