【DFS剪枝】

目录

可行性剪枝

最优性剪枝

重复性剪枝

奇偶性剪枝

生日蛋糕

练习

找数字

蒜头君的旅游计划

因数最多的数

置换的玩笑

Betsy的旅行

方块消消乐 


可行性剪枝

达到目标进行剪枝

#给定整数a1、a2、、an,判断是否可以从中选出若干数,使它们的和恰好为k
n=int(input())
a=list(map(int,input().split()))
k=int(input())
# 已经从前i项得到了和sum,然后对于i项之后的进行分支
def dfs(i,sum):
    if sum>k:#剪枝
        return False
    #如果前n项都计算过了,则返回sum是否与k相等
    if i==n:
        return sum==k
    #不加a[i]的情况
    if dfs(i+1,sum):
        return True
    #加上a[i]的情况
    if dfs(i+1,sum+a[i]):
        return True
    #无论是否加上a[i]都不能凑成k就返回false
    return False

最优性剪枝

对于求最优解的一类问题,通常可以用最优性剪枝,比如在求解迷宫最短路的时候,如果发现当前的步数已经超过了当前最优解,那从当前状态开始的搜索都是多余的,因为这样搜索下去永远都搜不到更优的解。通过这样的剪枝,可以省去大量冗余的计算。

此外,在搜索是否有可行解的过程中,一旦找到了一组可行解,后面所有的搜索都不必再进行了,这算是最优性剪枝的一个特例。

迷宫

n,m=map(int,input().split())
sx,sy=map(int,input().split())
gx,gy=map(int,input().split())
maze=[]
vis=[[0]*m for i in range(n)]
for i in range(n):
    list1=list(input())
    maze.append(list1)
#print(maze)

ans=float('inf')
def dfs(x,y,step):
    global ans
    if step>=ans:#剪枝
        return
    if x==gx and y==gy:
        if step<ans:
            ans=step
        return
    for dx,dy in [(1,0),(-1,0),(0,-1),(0,1)]:
        nx=dx+x
        ny=dy+y
        if 0<=nx<n and 0<=ny<m and vis[nx][ny]!=1 and maze[nx][ny]!='#':
            vis[x][y]=1
            dfs(nx,ny,step+1)#必须走一步,故没有选与不选
            vis[x][y]=0
    return

dfs(sx,sy,0)
print(ans)

重复性剪枝

对于某一些特定的搜索方式,一个方案可能会被搜索很多次,这样是没必要的。

再来看这个问题:

给定n个整数,要求选出K个数,使得选出来的K个数的和为sum。

如果搜索方法是每次从剩下的数里选一个数,一共搜到第k层,那么1,2,3这个选取方法能被搜索到6次,这是没必要的,因为我们只关注选出来的数的和,而根本不会关注选出来的数的顺序,所以这里可以用重复性剪枝。

我们强制规定选出来的数的位置是递增的,在搜索的时候,用一个参数来记录上一次选取的数的位置,那么此次选择我们从这个数之后开始选取,这样最后选出来的方案就不会重复了。

当然,搜索的效率也要比直接二进制枚举更高。

奇偶性剪枝

奇偶性剪枝我们先来看一道题目:

有一个nxm大小的迷宫。其中字符'S'表示起点,字符,D'表示出口,字符'x,表示墙壁,字符'.,表示平地。你需要从's'出发走到'D',每次只能向上下左右相邻的位置移动,并且不能走出地图,也不能走进墙壁。每次移动消耗1时间,走过路都会塌陷,因此不能走回头路或者原地不动。现在已知出口的大门会在T时间打开,判断在0时间从起点出发能否逃离迷宫。

数据范围n, m < 10, T <50。

样例

4 4 5
S.X.
..X.
..XD
....

输出

NO

我们只需要用DFS来搜索每条路线,并且只需搜到T时间就可以了(这是一个可行性剪枝)。但是仅仅这样也无法通过本题,还需考虑更多的剪枝。

如上图所示,将nxm的网格染成黑白两色。我们记每个格子的行数和列数之和为x,如果x为偶数,那么格子就是白色,反之奇数时为黑色。容易发现相邻的两个格子的颜色肯定不一样,也就是说每走一步颜色都会不一样。更普遍的结论是:走奇数步会改变颜色,走偶数步颜色不变。
那么如果起点和终点的颜色一样,而T是奇数的话,就不可能逃离迷宫。同理,如果起点和终点的颜色不一样,而T是偶数的话,也不能逃离迷宫。遇到这两种情况时,就不用进行DFS 了,直接输出"NO"

n,m,t=map(int,input().split())
maze=[]
vis=[[0]*m for i in range(n)]
for i in range(n):
    list1=list(input())
    maze.append(list1)
for i in range(n):
    for j in range(m):
        if maze[i][j]=='S':
            sx,sy=i,j
        if maze[i][j]=='D':
            gx,gy=i,j
f=False
def dfs(x,y,cnt):
    global f
    if f:
        return
    if cnt==t and x==gy and y==gy:
        f=True
        return
    for dx,dy in [(0,1),(1,0),(-1,0),(0,-1)]:
        nx=dx+x
        ny=dy+y
        if 0<=nx<n and 0<=ny<m and vis[x][y]!=1 and maze[x][y]!='x':
            vis[x][y]=1
            dfs(nx,ny,cnt+1)
            vis[x][y]=0

#偶数步不变,奇数步变
#起点和终点同色,sx+sy+gx+gy的和为偶数,要想到终点不能变色,故步数必须为偶数,sx+sy+gx+gy+t的和为偶数
#起点和终点异色,sx+sy+gx+gy的和为奇数,要想到终点必须变色,故步数必须为奇数,sx+sy+gx+gy+t的和为偶数
#其他状况均不能到达终点,故需满足sx+sy+gx+gy+t的和为偶数
if (sx+sy+gx+gy+t)%2!=0: #奇偶性剪枝
    print('NO')
else:
    dfs(0, 0, 0)
    if f:
        print('YES')
    else:
        print('NO')

生日蛋糕

 

n,m=map(int,input().split())
#cnt:当前层数
#v:当前体积
#s:当前面积
#r:当前圆柱体半径的上界
#h:当前圆柱体高的上界
ans=float('inf')
vmin=[0]*(m+1)
for i in range(1,m+1):
    vmin[i]=vmin[i-1]+i*i*i

def dfs(cnt,v,s,r,h):
    global ans
    if cnt==m:
        if v==n:
            ans=min(ans,s)
        return
    if vmin[m-cnt]+v>n:#可行性剪枝
        return
    if 2*(n-v)/r+s>ans:#最优性剪枝
        return
    for nr in range(r,m-cnt-1,-1):
        for nh in range(h,m-cnt-1,-1):
            ns=s+2*nr*nh
            nv=v+nr*nr*nh
            if nv>n:#可行性剪枝
                continue
            if cnt==0:
                ns+=nr*nr
            dfs(cnt+1,nv,ns,nr-1,nh-1)

r=int(n**0.5+0.5)#r最大时,h=1
dfs(0,0,0,r,n)
print(ans)

练习

找数字

在这里插入图片描述

n=int(input())

f=False
def dfs(m,cnt):
    global f
    if f:#最优性剪枝,当已经找到了一种可行性解的时候,就没有必要继续搜索了
        return
    if cnt>=19:#递归出口1,字符串的长度超出18。
        return
    if m%n==0:#递归出口2,找到了一种可行性答案。
        f=True
        print(m)
        return
    dfs(m*10+0,cnt+1)
    dfs(m*10+1,cnt+1)

dfs(1,1)

蒜头君的旅游计划

马上就要放寒假了,蒜头君已经辛勤的工作一年了,打算和家人一起出去旅游放松放松。有经验的人一定知道,出去旅游前一定要有详细的旅行规划。蒜头君打算旅游 n 个城市,但并不是每条路线的花费都是一样的。蒜头君是一个勤俭节俭的人,他就在想怎么把所有的城市旅游一遍花费最小呢?(蒜头君不喜欢重复旅游同一个城市,也就是说已到达过的城市蒜头君是不会再次光临的)
输入格式
第一行输入一个整数 n (1≤n≤15),表示有 n 个城市。

接下来有一个 n×n 的矩形,表示每两个城市之间的火车花费,每两个城市之间的花费不会超过 10000。

输出格式
输出一个整数,表示从 1 号城市把所有景点旅游一遍并且回到 1 号城市的最小花费。

样例输入

4
0 1 1 1
1 0 2 1
5 5 0 6
1 1 3 0

样例输出

8

n=int(input())
maze=[]
for i in range(n):
    list1=list(map(int,input().split()))
    maze.append(list1)
vis=[0]*n
ans=float("inf")
def dfs(x,sums,cnt):
    global ans
    if cnt==n:#递归出口
        ans=min(ans,sums+maze[x][0])
        return
    if sums>=ans:#最优性剪枝
        return
    vis[x]=1#注意,从x到i,需先将x标记,防止for中再次选中
    for i in range(n):
        if vis[i]!=1:
            dfs(i,sums+maze[x][i],cnt+1)
    vis[x]=0
dfs(0,0,1)
print(ans)

因数最多的数

题目

在这里插入图片描述

思路

1.如何求因数的个数

在1到n的所有数中,满足2式值最大且1式不超过n的数为因数最多的数。

规定1式的值为x,2式的值为cnt

2.如何确定质数的范围

我们可以发现前 15个质数之积已经大于 10^16所以我们枚举这 15 个质数就足够了。

3.如何使得所求数字尽可能小

当越小的数字的次数越大时,所得数会最小,既:
p1 < p2 < p3 < p4 < …… < pk
a1>=a2>=a3>=a4>=……>=ak

72=(2**3)*(3**2)的因数个数=(3+1)*(2+1)

108=(2**2)*(3**3)的因数个数=(2+1)*(3+1)

72<108 但 因数个数却相等

既:
第 i个质数的次数一定大于第 i+1个质数的次数

t=int(input())
p=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]#15个一次方质因数相乘大于10^16,故只取前15
# n:给定的数值范围
# m:当前数最大可以到多少次方
# x:当前数已经有多大了
# d:当前选到了那个质数,p的下标
# cnt:当前的因子数量是多少
def dfs(n,m,x,d,cnt):#(数值范围,因数最大次方,当前数已经有多大了,p中下标,因数个数)
    global maxn,ans
    #如果当前因子数更大,更新因字数,最小数更新为当前数
    if cnt>maxn:#因数个数大于目前最大值
        maxn=cnt#更新因数最值
        ans=x#更新目标值
        #并未确定达到最值,故不进行return
    elif cnt==maxn and x<ans:
        ans=x
    if d==15:
        return#当所有质数都循环完时,return;
    for i in range(1,m+1):#p中第d个元素选择要乘的次数
        x=x*p[d]
        if x>n:#之后的结果肯定都大于x,故break结束循环
             break
        dfs(n,i,x,d+1,cnt*(i+1))#传i是为了满足后面大的质因数的次方要小于前面小的,这样可以
        #保证所得结果的因数是最大的,因为质因数越小,次方越大,因数越多。

for i in range(t):
    n=int(input())
    maxn = 0
    ans=0
    dfs(n,60,1,0,1)#由于2^60已经大于10^16,所以质数为2时,最大的次数为60次方
    print(ans)

置换的玩笑

题目大意:

小蒜头又调皮了。这一次,姐姐的实验报告惨遭毒手。

姐姐的实验报告上原本记录着从 1 到 n 的序列,任意两个数字间用空格间隔。但是“坑姐”的蒜头居然把数字间的空格都给删掉了,整个数字序列变成一个长度为 1 到 100 的且首部没有空格的数字串。

现在姐姐已经怒了,蒜头找你写个程序快点把试验数据复原。

输入:

输入文件有一行,为一个字符串——被蒜头搞乱的实验数据。

字符串的长度在 1 到 100 之间。

输出:

输出共一行,为姐姐的原始测试数据—— 1 到 n 的输出。

任意两个数据之间有一个空格。

如果有多组符合要求的正确解,输出其中任意一组即可。

本题答案不唯一,符合要求的答案均正确

样例输入:

4111109876532

样例输出

4 1 11 10 9 8 7 6 5 3 2

解题思路:

因为字符串的长度不超过100,可以计算出n最大是54,我们只需要枚举一位数和两位数。

先通过字符串的长度计算出n,开一个数组标记枚举过的数,只有没标记过的数并且小于等于n才会存下来继续往后搜。

超时。。。

但是对于字符串s[x]+s[x+1],s[x:x+2]前者必须限制在x<=n-2,后者则不用。

s=input()
n=len(s)
vis=[0]*100
vis[0]=1
f=False
#x:现在在那一位
#cnt:已经分出多少数
def dfs(x,s1):
    global f
    if f:
        return
    if x>=n:
        f=True
        print(*s1)
        return

    if vis[int(s[x])]!=1:
        vis[int(s[x])]=1
        dfs(x+1,s1+[int(s[x])])
        vis[int(s[x])]=0
    if  vis[int(s[x:x+2])]!=1:
        vis[int(s[x:x+2])]=1
        dfs(x + 2, s1+[int(s[x:x+2])])
        vis[int(s[x:x + 2])] = 0

dfs(0,[])
s=input()
n=len(s)
vis=[0]*100
vis[0]=1
f=False
#x:现在在那一位
#cnt:已经分出多少数
def dfs(x,s1):
    global f
    if f:
        return
    if x>=n:
        f=True
        print(*s1)
        return
    #print(s[x],s[x]+s[x+1],s[x:x+2])
    if vis[int(s[x])]!=1:
        vis[int(s[x])]=1
        dfs(x+1,s1+[int(s[x])])
        vis[int(s[x])]=0
    if x<=n-2:
        if  vis[int(s[x]+s[x+1])]!=1:
            vis[int(s[x]+s[x+1])]=1
            dfs(x + 2, s1+[int(s[x]+s[x+1])])
            vis[int(s[x]+s[x+1])]=0


dfs(0,[])

优化

 因为序列从1开始递增排序,故只要确定好序列中数的个数就能确定最大值

s=input()
n=len(s)
vis=[0]*55
vis[0]=1
f=False
#x:现在在那一位
#cnt:已经分出多少数
def dfs(x,cnt,s1):
    global f
    if f:
        return
    if cnt==m:
        f=True
        print(*s1)
        return
    if x>=n:#剪枝
        return
    #print(s[x],s[x]+s[x+1],s[x:x+2])
    if int(s[x])<=m:#可行性剪枝
        if vis[int(s[x])]!=1:
            vis[int(s[x])]=1
            dfs(x+1,cnt+1,s1+[int(s[x])])
            vis[int(s[x])]=0
    if int(s[x:x+2]) <= m:#可行性剪枝
        if  vis[int(s[x:x+2])]!=1:
            vis[int(s[x:x+2])]=1
            dfs(x + 2,cnt+1,s1+[int(s[x:x+2])])
            vis[int(s[x:x + 2])] = 0
if n<=9:
    m=n#全部都是一位
else:
    m=(n-9)//2+9#一位两
dfs(0,0,[])

Betsy的旅行

 用普通DFS会超时

n=int(input())
sx,sy=0,0
gx,gy=n-1,n-1
vis=[[0]*n for i in range(n)]
def dfs(x,y,step):
    global ans
    if x==n-1 and y==0:
        if step==n*n:
            ans+=1
        return
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        nx = dx + x
        ny = dy + y
        if 0 <= nx < n and 0 <= ny < n and vis[nx][ny]!=1:
            vis[x][y]=1
            dfs(nx,ny,step+1)
            vis[x][y]=0
ans=0
dfs(0,0,1)
print(ans)

终点注意vis赋值的位置 

对vis赋值的位置还是有点迷( ̄﹏ ̄;)

经过多方面的必对可以确定,有for的情况下在for外面赋值,无for就在dfs上下

n=int(input())
# maze=[[0]*n for i in range(n)]
last=[[0]*n for i in range(n)]
vis=[[0]*n for i in range(n)]
for  i in range(n):
    for j in range(n):
        for di,dj in [(1,0),(-1,0),(0,1),(0,-1)]:
            ni=di+i
            nj=dj+j
            if 0<=ni<n and 0<=nj<n:
                last[i][j]+=1#统计每个格子周围有几个格子可以到达该格子
                #该格子周围每走过一格,就减一,要想满足一进一出,则周围至少还要有1个未走过的格子
# for i in range(n):
#     print(last[i])

def dfs(x,y,step):
    #到达x,y点
    global ans
    # for i in range(n):
    #     print(vis[i])
    # print(x,y)
    #vis[x][y] = 1放这里的话如果到终点没达到step==n*n要求则无法令终点处的vis[x][y] = 0
    if x==n-1 and y==0:
        if step==n*n:
            ans+=1
        return
    vis[x][y] = 1#注意放置位置
    dir=0
    #先对当前位置x,y的四周进行-1
    bx,by=0,0
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        nx = dx + x
        ny = dy + y
        if 0 <= nx < n and 0 <= ny < n and vis[nx][ny]!=1:
            last[nx][ny] -= 1#对当前位置x,y的四周进行-1
            if last[nx][ny]==1:#若周围减完1后存在=1的,就必须进入到该格子
                dir=1
                bx,by=nx,ny

    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:#遍历第下一个点
        nx = dx + x
        ny = dy + y
        if dir==1:
            if nx!=bx or ny!=by:
                continue
        if 0 <= nx < n and 0 <= ny < n and vis[nx][ny]!=1:
            r=0
            f=True
            for dx2, dy2 in [(1, 0), (-1, 0), (0, 1), (0, -1)]:#遍历第下一个点的周围
                nx2 = dx2 + nx
                ny2 = dy2 + ny
                if 0 <= nx2 < n and 0 <= ny2 < n and vis[nx2][ny2] != 1:
                    if last[nx2][ny2]<2:#如果第二个点有=1的,说当nx跳到nx2时该值会减为0,故该nx不可取
                        f=False
                        break
                    elif last[nx2][ny2]==2:#第二个点必须走的点的个数
                        r+=1
            if r<=1 and f:#nx可以走,且必须要走的点不能超过一个
                #vis[x][y] = 1 #放这里不行
                dfs(nx,ny,step+1)
                #vis[x][y]=0 #放这里不行因为对于点x,y的所有点还没有遍历结束,不能让vis[x][y]=0
    vis[x][y] = 0#注意放置位置
    #回溯还原
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        nx = dx + x
        ny = dy + y
        if 0 <= nx < n and 0 <= ny < n and vis[nx][ny]!=1:
            last[nx][ny] += 1

ans=0
last[n-1][0]+=1
# print(last)
dfs(0,0,1)
print(ans)

方块消消乐 

 

 

 

 

 关键信息:左下角为(0,0);x横y纵;只能左右移动;有重力;棋盘为7行5列;颜色小于10种;x,y要小,g要大。

 注意棋盘按正常坐标轴是倒过来的

解决这道题首先要掌握两个要点:

1,单行单列连续同色块的清除

n=5
maze=[]
for i in range(n):
    list1=list(map(int,input().split()))
    maze.append(list1)
for i in range(n):
    print(maze[i])
print()
def drop():
    for x in range(5):
        for y in range(1,7):
            if maze[x][y]!=0 and maze[x][y-1]==0:
                maze[x][y-1]=maze[x][y]
                maze[x][y]=0
def clear():#注意x是行y是列
    #查找所有横向连通块
    flag=0
    for x in range(3):#往右延申2格查找,故只需枚举前3列
        for y in range(7):
            if maze[x][y]!=0:#如果有颜色
                x2=x
                while x2+1<5 and maze[x2][y]==maze[x][y]:#在某一行中查找连续同色的个数
                    x2+=1
                if x2-x>2:#行方向有超过3个的连续同色块
                    for tx in range(x,x2+1):#在连续色块中向上向下列搜索
                        up,dn=y,y
                        #向上查找连续同色个数
                        while up+1<7 and maze[tx][up+1]==maze[x][y]:
                            up+=1
                        # 向下查找连续同色个数
                        while dn-1>=0 and maze[tx][dn-1]==maze[x][y]:
                            dn-=1
                        #print(tx,up,dn)
                        if up-dn>=2:#列方向有超过3个的连续同色块
                            #print(dn,up+1)
                            for ty in range(dn,up+1):#开始清除列上连续同色块
                                maze[tx][ty]=0
                                print(1)
                    for tx in range(x,x2+1):#开始清除行上连续同色块
                        maze[tx][y]=0
                        #print(1)
                    flag=1
    # 查找所有纵向向连通块
    for x in range(5):#往右延申2格查找,故只需枚举前3列
        for y in range(5):
            if maze[x][y]!=0:#如果有颜色
                y2=y
                while y2+1<7 and maze[x][y2]==maze[x][y]:#在某一行中查找连续同色的个数
                    y2+=1
                if y2-y>2:#行方向有超过3个的连续同色块
                    #print(y2)
                    for ty in range(y,y2+1):#在连续色块中向上向下列搜索
                        ri,lf=x,x
                        #向右查找连续同色个数
                        while ri+1<5 and maze[ri+1][ty]==maze[x][y]:
                            ri+=1
                        # 向左查找连续同色个数
                        while lf-1>=0 and maze[lf-1][ty]==maze[x][y]:
                            lf-=1
                        if ri-lf>=2:#行方向有超过3个的连续同色块
                            for tx in range(lf,ri+1):#开始清除行上连续同色块
                                maze[tx][ty]=0
                                #print(1)
                    for ty in range(y,y2+1):#开始清除列上连续同色块
                        maze[x][ty]=0
                        #print(1)
                    flag=1
    if flag:#执行了清楚
        return True
    else:#没有执行清楚
        return False


while clear():
    print(1)
    drop()
for i in range(n):
    print(maze[i])

# 1 0 0 0 0 0 0
# # 0 0 0 0 0 0 0
# # 1 0 0 0 0 0 0
# # 2 3 2 0 0 0 0
# # 1 2 3 3 0 0 0

2, python中实现c语言中的memcpy()函数

介于python没有c语言有memcpy可以单独开辟空间来复制列表

所以我用python实现相似的功能,使得每一层搜索都会在该层产生一个新的temp列表空间,来对maze进行回溯,且并不会影响其他层的状态。

#dfs()
#注意每个dfs中都会独立建立一个互不影响的temp,地址不一样。
temp=[[0]*7 for i in range(5)]#建立一个单独的内存地址用来存储此时maze的状态
for i in range(5):
    for j in range(7):
        temp[i][j]=maze[i][j]
#修改maze
#dfs()
#回溯还原maze
for i in range(5):
    for j in range(7):
        maze[i][j]=temp[i][j]

不知道错那了,/(ㄒoㄒ)/~~

PS:花了一天时间终于搞定了φ(゜▽゜*)♪

n=int(input())
maze=[[0]*7 for i in range(5)]

for i in range(5):
    list1=list(map(int,input().split()))
    for j in range(len(list1)):
        maze[i][j]=list1[j]

# for i in range(5):
#     print(maze[i])
ans={}
f=False

def empty():
    for i in range(len(maze)):
        for j in range(len(maze[0])):
            if maze[i][j]!=0:
                return False
    return True

def drop():
    for x in range(5):
        for y in range(1,7):
            if maze[x][y]!=0 and maze[x][y-1]==0:
                maze[x][y-1]=maze[x][y]
                maze[x][y]=0
    # num=[[-1]*10 for i in range(10)]
    # for x in range(5):
    #     h=0
    #     for y in range(7):
    #         if maze[x][y]:
    #             h+=1
    #             num[x][h]=y #建立一个二维列表,将maze中非0的值从下往上依次排列
    # for x in range(5):
    #     for y in range(7):
    #         if num[x][y]==-1:
    #             maze[x][y]=0
    #         else:
    #             maze[x][y]=maze[x][num[x][y]]

def clear():#注意x是行y是列
    #查找所有横向连通块
    # for i in range(5):
    #     print(maze[i])
    # print('c')
    flag=0
    for x in range(3):#往右延申2格查找,故只需枚举前3列
        for y in range(7):
            if maze[x][y]!=0:#如果有颜色
                x2=x
                while x2+1<5 and maze[x2][y]==maze[x][y]:#在某一行中查找连续同色的个数
                    x2+=1
                if x2-x>2:#行方向有超过3个的连续同色块
                    for tx in range(x,x2+1):#在连续色块中向上向下列搜索
                        up,dn=y,y
                        #向上查找连续同色个数
                        while up+1<7 and maze[tx][up+1]==maze[x][y]:
                            up+=1
                        # 向下查找连续同色个数
                        while dn-1>=0 and maze[tx][dn-1]==maze[x][y]:
                            dn-=1
                        #print(tx,up,dn)
                        if up-dn>2:#列方向有超过3个的连续同色块
                            #print(dn,up+1)
                            for ty in range(dn,up+1):#开始清除列上连续同色块
                                maze[tx][ty]=0
                                #print(1)
                    for tx in range(x,x2+1):#开始清除行上连续同色块
                        maze[tx][y]=0
                        #print(1)
                    flag=1
    # 查找所有纵向向连通块
    for x in range(5):#往右延申2格查找,故只需枚举前3列
        for y in range(5):
            if maze[x][y]!=0:#如果有颜色
                y2=y
                while y2+1<7 and maze[x][y2]==maze[x][y]:#在某一行中查找连续同色的个数
                    y2+=1
                if y2-y>2:#行方向有超过3个的连续同色块
                    for ty in range(y,y2+1):#在连续色块中向上向下列搜索
                        ri,lf=x,x
                        #向右查找连续同色个数
                        while ri+1<5 and maze[ri+1][ty]==maze[x][y]:
                            ri+=1
                        # 向左查找连续同色个数
                        while lf-1>=0 and maze[lf-1][ty]==maze[x][y]:
                            lf-=1
                        if ri-lf>2:#行方向有超过3个的连续同色块
                            for tx in range(lf,ri+1):#开始清除行上连续同色块
                                maze[tx][ty]=0
                    for ty in range(y,y2+1):#开始清除列上连续同色块
                        maze[x][ty]=0
                    flag=1
    # for i in range(5):
    #     print(maze[i])
    # print('e')
    if flag:#执行了清楚
        return True
    else:#没有执行清楚
        return False

def dfs(step):
    #print(step)
    #print(step)
    #print(1)
    global f
    #print(maze)
    if f:
        return
    if step==n:
        # print(ans)
        # for i in range(5):
        #     print(maze[i])
        if empty():
            f=True
            for i in range(n):
                print(ans[i])#x,y,g
        return
    sum=[0]*11
    for x in range(5):
        for y in range(7):
            sum[maze[x][y]]+=1
    for i in range(1,11):
        if sum[i]!=0 and sum[i]<3:#遍历所有颜色个数,有小于3的就无法清零
            f=False
            return
    for x in range(5):
        for y in range(7):
            # for i in range(5):
            #     print(maze[i])
            #print()
            #print(maze[x][y])
            if maze[x][y]==0:
                continue
            #右移
            #print(x, y)
            if x!=4:#如果坐标不在右边界,首先选择向右交换
                if maze[x + 1][y]!=maze[x ][y]:
                    ans[step] = [x, y, 1]  # 存步数
                    # 进行交换
                    # for i in range(5):
                    #     print(maze[i])
                    # print()
                    # temp = maze.copy()
                    temp=[[0]*7 for i in range(5)]
                    for i in range(5):
                        for j in range(7):
                            temp[i][j]=maze[i][j]
                    t=maze[x][y]
                    maze[x][y]=maze[x + 1][y]
                    maze[x + 1][y]=t
                    #print(maze[x][y],maze[x + 1][y])
                    # for i in range(5):
                    #     print(maze[i])
                    # print()
                    drop()#下落
                    # for i in range(5):
                    #     print(maze[i])
                    # print()
                    while clear():
                        drop()
                    # for i in range(5):
                    #     print(maze[i])
                    # print()
                    dfs(step+1)
                    for i in range(5):
                        for j in range(7):
                            maze[i][j]=temp[i][j]
            #右移
            if x!=0 and maze[x-1][y]==0:#坐标不在左边界,且左边为0才能换,不然不满足g最大
                if maze[x -1][y]!=maze[x ][y]:
                    # for i in range(5):
                    #     print(maze[i])
                    # print(1)
                    ans[step]=[x,y,-1]#存步数
                    # 进行交换
                    # temp =maze.copy()
                    temp=[[0]*7 for i in range(5)]
                    for i in range(5):
                        for j in range(7):
                            temp[i][j]=maze[i][j]
                    t=maze[x][y]
                    maze[x][y]=maze[x - 1][y]
                    maze[x - 1][y]=t
                    # for i in range(5):
                    #     print(maze[i])
                    # print(2)
                    drop()
                    # for i in range(5):
                    #     print(maze[i])
                    # print(3)
                    while clear():#如果执行了清除,就执行下落
                        # print(x)
                        drop()
                    # for i in range(5):
                    #     print(maze[i])
                    # print(4)
                    dfs(step+1)
                    for i in range(5):
                        for j in range(7):
                            maze[i][j]=temp[i][j]
temp=[]
dfs(0)
# print(ans)
# if f!=True:
#     print(-1)
# for i in range(5):
#     print(maze[i])
# 2
# 0
# 1 0
# 1 0
# 2 3 2 0
# 1 2 3 3 0

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DFS深度优先搜索)是一种常见的图遍历算法,它使用递归或栈的方式,从一个顶点出发,沿着一条路径一直到达最深的节点,然后回溯到上一层继续遍历其他节点。DFS常被用于解决图的连通性问题、路径问题等。在实际应用中,可以使用DFS进行状态搜索、图的遍历、拓扑排序等。 剪枝是指在搜索过程中,通过一系列的策略判断,提前终止当前搜索分支,并跳过一些无用的搜索路径,从而减少搜索时间。剪枝的核心在于提前排除某些明显不符合条件的状态,以减少无效搜索的时间开销,提高效率。在算法设计中,剪枝通常会利用一些特定的性质或条件进行判断,从而缩小搜索空间。 动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划通常用于求解最优化问题,它通过定义状态和状态转移方程,采用自底向上的思路,逐步求解每个子问题的最优值,最终得到原问题的最优解。动态规划的核心是存储已经计算过的子问题的解,避免了重复计算。 贪心算法是一种基于局部最优解的策略,它通过每一步选择在当前状态下最优的解,以期望得到全局最优解。贪心算法的基本思想是由局部最优解推导出全局最优解,通常通过贪心选择性质、最优子结构和贪心选择构成三部分。贪心算法相比其他算法,如动态规划,它的优势在于简单、高效,但缺点在于不能保证获取到全局最优解,只能得到一个近似解。 综上所述,DFS剪枝、动态规划和贪心算法算法设计和问题求解中都发挥着重要的作用。具体使用哪种算法取决于问题的性质和要求,需要在实际应用中进行综合考虑和选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值