赞
踩
输出自然数1到n所有不重复的排列,即n的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
输入 n(1≤n≤9)
由1~n组成的所有不重复的数字序列,每行一个序列。每个数字占5列。
4
- 1 2 3 4
- 1 2 4 3
- 1 3 2 4
- 1 3 4 2
- 1 4 2 3
- 1 4 3 2
- 2 1 3 4
- 2 1 4 3
- 2 3 1 4
- 2 3 4 1
- 2 4 1 3
- 2 1 4 3
- 3 1 2 4
- 3 1 4 2
- 3 2 1 4
- 3 2 4 1
- 3 4 1 2
- 3 4 2 1
- 4 1 2 3
- 4 1 3 2
- 4 2 1 3
- 4 2 3 1
- 4 3 1 2
- 4 3 2 1

因为是全排列问题,首先最坏实现可以是暴力解,输入n,直接嵌套n个for即可,当然这样肯定是行不通的,遇到排列组合的题目,我们首先要考虑回溯算法,即(DFS),主要是使用递归来实现的,遇到递归题,肯定是要先判断它的终止条件的,因为本题是全排列问题,即退出条件就是当(step==n+1)时列表a肯定已经存放了n个元素即输出1~n的值,再通过回退来实现整个算法。回退是返回上一步递归,并将值清空,标记为未使用,这样就完成了整个全排列。
- #方法一:内置函数
- from itertools import *
- n=int(input())
- li=[]
- for i in range(1,n+1):
- li.append(str(i))
- for i in permutations(li):
- a=' '.join(i)
- print(' ',a)
-
- #方法二:回溯
- n=int(input())#输入的数
- a=[0 for _ in range(n+2)]#用来存放的列表
- used=[False for _ in range(n+2)] #用与记录是否有被用过
- def dfs(step):
- global n,a,used #全局变量
- if step==n+1: #终止条件
- #输出结果
- for i in range(1,n+1):
- print("%5d"%a[i],end="")
- print()#换行
- for j in range(1,n+1):
- if not used[j]: #判断是否有使用
- a[step]=j #修改a列表的数
- used[j]=True #修改牌的状态为y已经使用
- dfs(step+1) #继续走到第step+1个盒子上
- used[j]=False #递归结束,返回上一个盒子,修改牌的状态为没有使用
- dfs(1)

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r<=n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
现要求你用递归的方法输出所有组合。
例如n=5,r=3,所有组合为:
l 2 3 l 2 4 1 2 5 l 3 4 l 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
一行两个自然数n、r(1<n<21,1<=r<=n)。
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
5 3
- 1 2 3
- 1 2 4
- 1 2 5
- 1 3 4
- 1 3 5
- 1 4 5
- 2 3 4
- 2 3 5
- 2 4 5
- 3 4 5
这道题和上一道题类似,只输出不重复的无序数(组合问题),根据上面那题可以得出结论(1 5 3有不同中解法135 153 513 531),而在本题中,这种数都算是重复的,而最小值是135,所以我们只需要找有序列,即只需寻找当前手中的牌比上一个盒子中的牌要大即可。
- n,m=map(int,input().split())
- a=[0 for _ in range(n+2)]
- used=[False for _ in range(n+2)]
- def dfs(step):
- global n,a,used
- if step==m+1:
- for i in range(1,m+1):
- print(a[i],end="")
- print()
- #枚举手中的n个牌,当前编号一定大于上一个盒子的编号(i>a[step-1])
- for i in range(a[step-1]+1,n+1):
- if not used[i]:
- a[step]=i
- used[i]=True
- dfs(step+1)
- used[i]=False
- dfs(1)

将M个白棋子与N个黑棋子排成一行,可以排成多种不同的图案。例如:2个白棋子和2个黑棋子,一共可以排成如下图所示的6种图案(根据组合数计算公式:)
请你编写一段程序,输出M个白棋子与N个黑棋子能够组成的所有图案。
为了避免程序输出结果过多导致严重超时,特别限制:1≤M,N≤6
两个正整数M,N表示白棋子与黑棋子的数量,并且满足1≤M,N≤6
M个白棋子与N个黑棋子可以排列的所有图案。
要求:每行输出一种图案,白棋子用0表示,黑棋子用1表示,按升序输出
- 【测试样例1】
- 2 1
- 【测试样例2】
- 2 2
- 【测试样例3】
- 2 3
- 【测试样例1】
- 001
- 010
- 100
- 【测试样例2】
- 0011
- 0101
- 0110
- 1001
- 1010
- 1100
- 【测试样例3】
- 00111
- 01011
- 01101
- 01110
- 10011
- 10101
- 10110
- 11001
- 11010
- 11100

这道题我本来想着是创建一个列表,将m个0和n个1都存储起来,然后再根据上面的步骤,依次输出,但输出结果有许多重复值(001、001),程序里并没有因为两个相同的数而节省步骤,所以需要改变思想,删除重复的值,因为只有0和1两个值,所以只需要遍历这两种值即可,将used的值改为存放0和1的数量。使用了就减一,回退就加一,和上面的程序类似。
- m,n=map(int,input().split())#输入的数
-
- a=[0 for _ in range(n+m+2)]#用来存放的列表
- used=[m,n] #表示两种棋子的数量
-
- def dfs(step):
- global a,used,m,n #全局变量
- if step==m+n+1:
- for i in range(1,m+n+1):
- print(a[i],end="")
- print()
- #因为只有0和1两种棋子,所以只需要遍历棋子的种类
- for i in range(2):
- if used[i]>0:
- a[step]=i
- used[i]-=1 #使用过就减1
- dfs(step+1)
- used[i]+=1 #回溯加一
- dfs(1)

设R={ r1, r2 , …, rn}是要进行排列的n个小写字母。其中小写字母r1, r2 , …, rn可能相同。试设计一个算法,列出R的所有不同排列。
给定n 以及待排列的n 个小写字母。计算出这n 个小写字母的所有不同排列。
输入数据的第1 行是小写字母个数n,1≤n≤500。接下来的1 行是待排列的n个元素。
计算出的n个小写字母的所有不同排列并按字典序输出。文件最后1行中的数是排列总数。
- 4
- aacc
- aacc
- acac
- acca
- caac
- caca
- ccaa
- 6
这道题和上一道题类似,只需要创建一个26个字母的列表,和上步一样的操作即可
- n=int(input()) #输入字符长度
- m=input() #字符
- a=[0 for _ in range(n+2)]#用来存放的列表
- used=[0 for _ in range(27)] #表示26个字母的空列表
- for i in m: #记录i中的字母个数,从1开始计算
- used[ord(i)-ord('a')+1]+=1
- count=0 #计数
- def dfs(step):
- global a,used,n,count #全局变量
- if step==n+1:
- for i in range(1,n+1):
- print(chr(96+a[i]),end="") #转为字母
- print()
- count+=1
- for i in range(len(used)):
- if used[i]>0:
- a[step]=i
- used[i]-=1 #使用过就减1
- dfs(step+1)
- used[i]+=1 #回溯加一
- dfs(1)
- print(count)

在N*N的棋盘上放置N个皇后(n<=10)而彼此不受攻击(即在棋盘的任一行,任一列和任一对角线上不能放置2个皇后),编程求解所有的摆放方法。
输入:n
每行输出一种方案,每种方案顺序输出皇后所在的列号,每个数占5列。若无方案,则输出no solute!
4
- 2 4 1 3
- 3 1 4 2
本题主要考虑皇后的放置问题,当放下皇后,行列和对角线都不能再放置,所以需要增加行列和对角线的列表,因为对角线上,数都是相同的,并且对角线分为两种,一种是上对角线(行等于列),还有一种是下对角线(行-列+所数入的数-1),得到这些就好做了,套用回溯模版即可。
- #方法一
- n=int(input())
-
- #创建一个列表,表示当前位置 pace[0]=1表示标记第一行第二列的值
- pace=[0 for _ in range(n)]
-
- #创建列
- flat=[0 for _ in range(n)]
-
- #创建对角线,分上下对角线
- d1=[0 for _ in range(2*n-1)]
- d2=[0 for _ in range(2*n-1)]
- count=0 #计数
- #输出
- def printf(pace):
- for i in range(n):
- for j in range(n):
- if pace[i]==j:
- print("%5d"%(j+1),end="")
- print()
-
- def dfs(row): #行
- global count,d1,d2,flat,pace
- for col in range(n): #遍历列
- #满足条件就放数,
- if flat[col]==0 and d1[row+col]==0 and d2[row-col+n-1]==0:
- pace[row]=col
- #将使用过的点都标记为1
- flat[col]=1
- d1[row+col]=1
- d2[row-col+n-1]=1
- #如果不是最后一行,递归
- if row<n-1:
- dfs(row+1)
- #最后一行
- else:
- count+=1
- printf(pace)
- #回溯,将点清0
- flat[col]=0
- d1[row+col]=0
- d2[row-col+n-1]=0
- dfs(0)
- if count==0:#如果没有值,输出
- print('no solute!')
'运行
- #方法二:不同书写
- n=int(input())
-
- #创建一个列表,表示当前位置 pace[0]=1表示标记第一行第二列的值
- pace=[0 for _ in range(n)]
-
- #创建列
- flat=[0 for _ in range(n)]
-
- #创建对角线,分上下对角线
- d1=[0 for _ in range(2*n-1)]
- d2=[0 for _ in range(2*n-1)]
- count=0 #计数
-
- def dfs(row): #行
- global count,d1,d2,flat,pace,n
- if row==n:
- count+=1
- for i in range(n):
- print("%5d"%(pace[i]+1),end="")
- print()
- return
- for col in range(n): #遍历列
- #满足条件就放数,
- if flat[col]==0 and d1[row+col]==0 and d2[row-col+n-1]==0:
- pace[row]=col
- #将使用过的点都标记为1
- flat[col]=1
- d1[row+col]=1
- d2[row-col+n-1]=1
- #递归
- dfs(row+1)
- #回溯,将点清0
- flat[col]=0
- d1[row+col]=0
- d2[row-col+n-1]=0
-
- dfs(0)
- if count==0:#如果没有值,输出
- print('no solute!')
'运行
给定一个M*M(2≤M≤9)的迷宫,迷宫用0表示通路,1表示围墙。
迷宫的入口和出口分别位于左上角和右上角,入口和出口显然都是0。
在迷宫中移动可以沿着上、下、左、右四个方向进行,前进格子中数字为0时表示可以通过,为1时表示围墙不可通过,需要另外再找找路径。
请统计入口到出口的所有路径(不重复),并输出路径总数。若从入口无法到达出口,请输出0。
第一行输入1个正整数M(≤M≤9),表示迷宫是M行M列。
第2行到第n+1行是一个M阶的0-1方阵。
统计入口到出口的所有路径(不重复),并输出路径总数。若从入口无法到达出口,请输出0。
- 3
- 0 0 0
- 1 0 1
- 0 0 1
1
走迷宫问题,首先就是将迷宫转换为二维数组的形式,因为有上下左右四个方向可以走,所以可以创建一个匿名函数,表示上下左右的移动,接着就是判断新走的点是否在迷宫中,并且为0,如果能走,就一直往下走,当前面没有路(1),则回退。最后要注意一点就是,要将起点标记为1,表示已经走过,不然会进行重复计算,就是因为这个错误就一直没有答对。
- n=int(input())
- maze=[] #迷宫
- #搭建迷宫
- for i in range(n):
- li=list(map(int,input().split()))
- maze.append(li)
- #print(maze)
- #创建上下左右四个方向寻找
- dirs=[
- lambda x,y:(x+1,y), #下
- lambda x,y:(x-1,y), #上
- lambda x,y:(x,y+1), #右
- lambda x,y:(x,y-1) #左
- ]
- x1,y1=0,0 #起点坐标
- x2,y2=0,n-1 #终点坐标
- count=0 #计数
-
- def dfs(x1,y1,x2,y2):
- global count
- #当起点和终点的值一样时,即找到一条路
- if x1==x2 and y1==y2:
- count+=1
- nextNode=[] #下一个点
- #寻找四个方向上的点
- for dir in dirs:
- nextNode=dir(x1,y1)
- #判断边界条件以及迷宫上的数
- if 0<=nextNode[0]<=n-1 and 0<=nextNode[1]<=n-1 \
- and maze[nextNode[0]][nextNode[1]]==0:
- maze[nextNode[0]][nextNode[1]]=1 #标记已经走过
- dfs(nextNode[0],nextNode[1],x2,y2) #下一点
- maze[nextNode[0]][nextNode[1]]=0 #回溯,清0
- maze[0][0]=1 #将起点标记为已经走过,不然会进行重复计算,报错
- dfs(x1,y1,x2,y2)
- print(count)

任何一个大于1的自然数n(n <= 10),总可以拆分成若干个小于n的自然数之和。
当n=7共14种拆分方法:
7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+1+3
7=1+1+1+2+2
7=1+1+1+4
7=1+1+2+3
7=1+1+5
7=1+2+2+2
7=1+2+4
7=1+3+3
7=1+6
7=2+2+3
7=2+5
7=3+4
输入自然数n
输出拆分的方案
7
- 1+1+1+1+1+1+1
- 1+1+1+1+1+2
- 1+1+1+1+3
- 1+1+1+2+2
- 1+1+1+4
- 1+1+2+3
- 1+1+5
- 1+2+2+2
- 1+2+4
- 1+3+3
- 1+6
- 2+2+3
- 2+5
- 3+4
类似第三题组合题,当前数一定大于等于上一个数(不重复),并且拆数块一定大于2。
- n=int(input())
- a=[0 for _ in range(n+2)]
- def dfs(n,s):#需要分解的数,分解块数
- global a
- if n==0:
- if s<=2:
- return
- #取到倒数第二个数,因为后面有个+
- for i in range(1,s-1):
- print('%d+'%a[i],end="")
- #输出最后一位
- print(a[s-1])
- #print()
- for i in range(1,n+1):
- if i>=a[s-1]: #类似排序,所以只要找比上一个盒子大的数
- a[s]=i
- dfs(n-i,s+1)
- dfs(n,1)
'运行
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。