图论--广度优先搜索--python

#coding:utf-8
import scrapy
import xlwt, lxml
import re, json
import matplotlib.pyplot as plt
import numpy as np
import pylab
from scipy import linalg
from igraph import *
from collections import deque
#图论
'''
BFS(Breadth First Sreach)--广度优先搜索
    最简单\直接的图搜索算法
        从起点开始层层扩展
            第一层是离起点为1的
            第二层是离起点为2的
            ......
        本质就是按层(距离)扩展,无回退
        
BFS分析的两个要点

    结点判重:如果在扩展中发现某节点在前期已经访问过,则本次不再访问该节点;显然,第一次访问到该节点时,是访问次数最少的:最少,最短
    路径记录: 
        一个结点可能扩展出多个结点:多后继 a1a2... ; 但是任意一个结点最多只可能有一个前驱(起始结点没有前驱):单前驱
        用和结点数目等长的数组pre[0...N-1];
        pre[i]=j:第i个结点的前驱是j
        存索引,不存数据本身
        
BFS算法框架
    
    辅助数据结构:队列q;结点是第几次被访问到的d[0...N-1],简称步数
    算法描述:
    
    起点start入队q
        记录步数d[start]=0
        记录start的前驱pre[start]=-1
    如果队列q非空,则队首结点X出队,尝试扩展X
        找到X的邻接点集合{y|(x,y)属于E}
            对于每一个新扩展结点y判重,如果y是新结点,则入队q
            同时,记录步数d[y]=d[x]+1;前驱pre[y]=x  
'''

'''
单词变换问题 Word ladder
    给定字典和一个起点单词,一个终点单词,每次只能变换一个字母,问从起点单词是否可以到达终点单词?最短多少步?
    如,start='hit'
        end='cog'
        dict=['hot','dot','dog','lot','log']
    hit->hot->dot->dog->cog 
    
使用邻接表,建立单词间的联系
    单词为图的结点,若能够变换则,两个单词存在无向边
       -> 若单词A和B只有一个字母不同,则A-B存在边
    建图:
        预处理:
            1.对字典中的所有单词建立map,hash或者trie结构,利于后序的查找
            2.对于某单词w,单词中的第i位记为β,则将β替换为[β+1,z],查找新的串nw是否在字典中.如果在,将w-nw添加到邻接表项w和nw中(无向边)
            3.循环处理第二步
            //若使用map,串在字典中的查找认为是O(logN)的,那么,整体时间复杂度为O(N*len*13*logN),即O(N*logN);若使用hash或者trie,整体复杂度为O(N)
            
从起始单词开始,广度优先搜素,看能否达到终点单词.若可以,则这条路径上的变化是最快的
[虽然起点单词开始到终点单词的路径内的单词必须在字典内,但起点和终点本身没有要求]
'''

'''
#bfs
class Graph(object):
    def __init__(self):
        self.order=[]
        self.neighbor={}
    def add_node(self,node):
        key,val=node#邻接表的形式存储图
        if not isinstance(val,list):
            print('node should be a list')
        self.neighbor[key]=val
    def broadth_first(self,root):
        if root:
            search_queue=deque()
            search_queue.append(root)
            visited=[]
        else:
            print('root is None')
            return -1
        while search_queue:
            x=search_queue.pop(0)
            if not x in visited and x in self.neighbor.keys():#判重以及检查是否属于图中结点
                search_queue+=self.neighbor[x]
                visited.append(x)

'''



def wordLadder(start,end,wordlist):
    wordlist.append(start)
    wordlist.append(end)
    length=len(wordlist)
    # glist=[]
    glist2={}#每个结点可扩展的结点集合【邻接矩阵的形式】
    for i in range(0,length):
        w=wordlist[i]
        temp=[]
        for j in range(0,len(w)):
            for k in range(ord('a'),ord('z')):
            # for k in range(ord(w[j])+1,ord('z')):
                nw=w.replace(w[j],chr(k),1)
                if nw in wordlist and nw!=w:
                # if nw in wordlist :
                    temp.append(nw)
                    # glist.append((w,nw))
        glist2[w]=temp
    print(glist2)
    # print(glist)#有联系(能形成边,无向)的结点
    # g=Graph.TupleList(glist,directed=False,vertex_name_attr='name')
    # print(g)
    queue=[]
    d={}
    pre={}
    visited=[]
    queue.append(start)
    d[start]=0
    pre[start]=-1
    while queue:
        x=queue.pop(0)
        elist = glist2[x]
        for i in elist:
            if not i in visited and i!=start:
                queue.append(i)
                d[i]=d[x]+1
                pre[i]=x
                visited.append(i)
    print(pre)
    print(d)
    print(visited)
    order2=[]
    order2.append(end)
    def found(pre,start,end):
        x=pre[end]
        order2.append(x)
        if x == -1:
            return True
        found(pre,start,x)
    found(pre, start, end)
    print(order2)

# def getKey(dict,values):
#     return [k for k,v in dict.items() if v==values]
# wordLadder('hit','cog',['hot','dot','dog','lot','log'])

# print(ord('a'))#字母转换为Ascii数字
# print(chr(98))#Ascii数字转换为字母
# w='sstr'
# nw=w.replace(w[0],chr(ord(w[0])+1),1)
# print(nw)

'''
#周围区域问题:
    给定二维平面,格点处为'X'或'O'.求出所有由'X'围成的区域
    找到这样的区域后,将所有的O翻转成X即可
    eg:X X X X      X X X X
        X O O X -->  X X X X
        X X O X      X X X X
        X O X X      X O X X
    此处只考虑四位相邻
    
反向思考最简单:哪些’O‘ 是应该保留的?
    从上下左右四个边界往里走,凡是能碰到的’O‘,都是跟边界接壤的,应该保留
    
    思路:
    对于每一个边界上的'O'作为起点,做若干次广度优先搜素,对于碰到的'O',标记为其它某字符Y
    最后遍历一遍整个地图,把所有的Y恢复恢复成'O'
    把所有现有的'O'都改成'X'
'''

def aroundArea(matrix):
    top=matrix[0]
    bottom=matrix[-1]
    left=[i[0] for i in matrix[1:row_len-1]]
    right=[i[-1] for i in matrix[1:row_len-1]]

    for i in range(0,len(top)):
        if top[i]=='O':
            bfs(matrix,0,i)

    for i in range(0,len(bottom)):
        if bottom[i]=='O':
            bfs(matrix,row_len-1,i)

    for i in range(0,len(left)):
        if left[i]=='O':
            bfs(matrix,i+1,0)

    for i in range(0,len(right)):
        if right[i]=='O':
            bfs(matrix,i+1,col_len-1)
    # print(matrix)
    for i in range(0,row_len):
        for j in range(0,col_len):
            if(matrix[i][j]=='O'):
                matrix[i][j]='X'
            elif matrix[i][j]=='Y':
                matrix[i][j]='O'
    print(matrix)
    # print(top,bottom,left,right)
def bfs(matrix,row,col):
    queue=[]
    visited=[]
    queue.append((row,col))
    while queue:

        x=queue.pop(0)
        l = [(x[0] - 1, x[1]), (x[0] + 1, x[1]), (x[0], x[1] - 1), (x[0], x[1] + 1)]#相邻四位

        for i in l:
            if not i in visited:
                if i[0]>=0 and i[0]<row_len and i[1]>=0 and i[1]<col_len :
                    if matrix[i[0]][i[1]]=='O':
                        matrix[i[0]][i[1]]='Y'#标记为其它字符
                        queue.append(i)#只有相邻为'O',才入队
                visited.append(i)
    matrix[row][col]='Y'
    print(visited)

matrix=[['X','X','X','X','X'],['X','O','X','O','X'],['X','O','O','O','X'],['X','X','O','X','X']]
row_len=len(matrix)
col_len=len(matrix[0])
aroundArea(matrix)












 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值