IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【DFS剪枝】 -> 正文阅读

[数据结构与算法]【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()函数

#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

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:39:02  更:2022-10-22 21:44:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:50:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码