算法作业

这是一份关于《算法设计与分析》课程的详细作业总结,涵盖了算法概述、复杂性理论、递归、分治、动态规划、贪心算法、图算法等内容。通过实例分析了算法的正确性、时间复杂度、分摊费用、递归形式的算法修改以及动态规划应用。还讨论了如何用L形板平铺平板,机器人走动的动态规划解决方案,以及网络流与匹配问题的解决过程。

作业来自于MOOC《算法设计与分析》(张德富 曾华琳)

本课程主要介绍算法设计与分析的基本方法以及算法复杂性理论基础。通过本课程的学习,要求学生理解并熟练掌握递归与分治法、贪心法、动态规划方法、回溯法、分支定界法,以及高级图论算法、线性规划算法等,理解并掌握算法复杂性的分析方法、NP完全性理论基础等计算复杂性的基本知识及完备性证明概要。

第一周作业–算法概述及复杂性理论

  1. 给定一个算法,其输入是一个整数集S和一个整数m,输出是和为m的所有S的子集,算法步骤如下:(1)列出S的全部子集,求他们的和。(2)逐个查看步骤(1)列出的子集,把每个和等于m的子集输出。
    上述算法是否满足算法特点?说明理由。

满足有穷性、确切性、输入项、输出项和可行性。
因为S的子集个数是有限个,所以该算法总会在有限个步骤之后终止,所以满足有穷性;
该算法的步骤定义清楚,是计算机可以实现的步骤,所以满足确切性;
该算法的输入项为0,满足输入项;
该算法的输出为和等于m的子集,满足输出项;
该算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步,满足为有效性。

  1. . 利用循环不变量证明下述计算a^n算法的正确性:
Exp(a,n)
    i<-1
    pow<-1
    while i<=n do
         pow<-pow*a
         i<-i+1
    return pow

循环不变量:pow=a^(i-1)

初始步:循环开始之前,i=1,pow=1,a^0=1=pow,如果n=0,则不循环,返回1。若n=1,则循环一次,pow=a,满足要求

迭代:假设第k次迭代后,循环不变量满足要求,此时 p o w = a k , i = k + 1 pow=a^k , i=k+1 pow=ak,i=k+1
第k+1次迭代时, p o w = p o w ∗ a = a k + 1 , i = i + 1 = k + 2 pow=pow*a=a^{k+1}, i=i+1=k+2 pow=powa=ak+1,i=i+1=k+2,此时 a i − 1 = a k + 1 = p o w a^{i-1}=a^{k+1}=pow ai1=ak+1=pow,满足要求

终止: p o w = a n , i = n + 1 , 所 以 a i − 1 = a n = p o w pow=a^n,i=n+1,所以a^{i-1}=a^n=pow pow=an,i=n+1,ai1=an=pow,满足要求

  1. 设有两个在同一机器上实现的算法,运行时间分别为 100 n 2 和 2 n 100n^2和2^n 100n22n。当n取何值时,前者比后者快?
    由计算得:当n等于15时,100n2等于22500,2n=32768,前者比后者快

第二周作业–算法分析方法

1.对某个数据结构执行一个具有n个运算的序列。如果i为2的整数幂,则第i个运算的费用为i否则为1.使用合计方法确定每次运算的分摊费用。

C i C_i Ci为第i步实际的代价,则
∑ i = 1 n C i ≤ n + ∑ j = 0 l o g   n 2 j = n + ( 2 n − 1 ) < 3 n \sum_{i=1}^nC_i \leq n+ \sum_{j=0}^{log \ n}2^j = n+(2n-1) <3n i=1nCin+j=0log n2j=n+(2n1)<3n
所以每次分摊费用为 O ( 1 ) O(1) O(1)

  1. 用势能方法分析上题。

定义 C i C_i Ci为分摊代价, c i c_i ci为实际代价。设 i = 2 j + k i=2^j+k i=2j+k,定义第i个操作Di的势函数 Φ ( D i ) = 2 ∗ k 。 Φ(D_i)=2*k。 Φ(Di)=2k
当k=0时,实际代价 c i = i c_i=i ci=i, 这 时 i − 1 对 应 的 k 为 : 2 j − 2 j − 1 − 1 这时 i-1对应的k为: 2^j-2^{j-1}-1 i1k:2j2j11
所以
C i = c i + Φ ( D i ) − Φ ( D i − 1 ) = i + ( 0 − 2 ( 2 j − 2 j − 1 − 1 ) ) = i − ( 2 j ( 2 − 1 ) − 2 ) = i − i + 2 = 2 \begin{aligned} C_i &=c_i+Φ(D_i)-Φ(D_{i-1}) \\ &=i+(0-2(2^j-2^{j-1}-1)) \\ &=i-(2^j(2-1)-2) \\&=i-i+2 \\&=2 \end{aligned} Ci=ci+Φ(Di)Φ(Di1)=i+(02(2j2j11))=i(2j(21)2)=ii+2=2
当k=1时,实际代价为1
C i = c i + Φ ( D i ) − Φ ( D i − 1 ) = 1 + ( 2 k − 2 ( k − 1 ) ) = 3 \begin{aligned} C_i &=c_i+Φ(D_i)-Φ(D_{i-1}) \\ &=1+(2k-2(k-1)) \\&=3 \end{aligned} Ci=ci+Φ(Di)Φ(Di1)=1+(2k2(k1))=3
由上知,第i个操作的平摊代价为O(1)

第三周作业–递归

  1. 将插入排序算法更改为递归形式,并分析时间复杂度。
def insertSort(arr,n):
	if n == 0:
		return
	insertSort(arr,n-1)
	i = n 
	while i>0 and arr[i-1]>arr[i]:
		arr[i-1],arr[i] = arr[i],arr[i-1]
		i -=1

由代码易得公式:
f ( x ) = { T ( n ) = Θ ( 1 ) n = 1 T ( n ) = T ( n − 1 ) + Θ ( n ) n > 1 f(x)=\left\{ \begin{aligned} T(n) & = \Theta(1)\quad n=1 \\ T(n) & = T(n-1)+ \Theta(n) \quad n>1\\ \end{aligned} \right. f(x)={T(n)T(n)=Θ(1)n=1=T(n1)+Θ(n)n>1
所以时间复杂度为 Θ ( n 2 ) \Theta(n^2) Θ(n2)

  1. 修改Perm1使得生成子序列按照字典序排列。
P=[1,2,3]
n=3

def perm(m):
    if m==n:
        print(P)
    else:
        for j in range(m,n):
            P[m:]=sorted(P[m:]) # 对交换后的序列排序
            P[j],P[m] = P[m],P[j] 
            perm(m+1)
            P[j],P[m] = P[m],P[j] 
perm(0)
  1. 公式法求解以下递归方程: ( 1 ) T ( n ) = 4 T ( n / 2 ) + n 。 ( 2 ) T ( n ) = 4 T ( n / 2 ) + n 2 。 ( 3 ) T ( n ) = 4 T ( n / 2 ) + n 3 。 (1)T(n)=4T(n/2)+n。(2)T(n)=4T(n/2)+n^2。 (3)T(n)=4T(n/2)+n^3。 1T(n)=4T(n/2)+n(2)T(n)=4T(n/2)+n2(3)T(n)=4T(n/2)+n3

( 1 ) T ( n ) = 4 T ( n / 2 ) + n . a = 4 b = 2 f ( n ) = n   a n d n log ⁡ b a = n log ⁡ 2 4 = n 2 f ( n ) = O ( n log ⁡ b a − ϵ ) = O ( n log ⁡ 2 4 − 1 ) T ( n ) = Θ ( n 2 ) \begin{aligned} (1) T(n)&=4T(n/2)+n. \quad a=4 \quad b=2 \quad f(n)=n \ and \\ n^{\log_b^a}&=n^{\log_2^4}=n^2 \\ f(n)& =O(n^{\log_b^{a-\epsilon}})=O(n^{\log_2^{4-1}})\\ T(n)&=\Theta(n^2) \end{aligned} (1)T(n)nlogbaf(n)T(n)=4T(n/2)+n.a=4b=2f(n)=n and=nlog24=n2=O(nlogbaϵ)=O(nlog241)=Θ(n2)

( 2 ) T ( n ) = 4 T ( n / 2 ) + n 2 . a = 4 b = 2 f ( n ) = n 2   a n d n log ⁡ b a = n log ⁡ 2 4 = n 2 f ( n ) = Θ ( n log ⁡ b a ) = Θ ( n 2 ) T ( n ) = Θ ( n 2 lg ⁡ n ) \begin{aligned} (2) T(n)&=4T(n/2)+n^2. \quad a=4 \quad b=2 \quad f(n)=n^2 \ and \\ n^{\log_b^a}&=n^{\log_2^4}=n^2 \\ f(n)& =\Theta(n^{\log_b^a})=\Theta(n^2)\\ T(n)&=\Theta(n^2\lg n) \end{aligned} (2)T(n)nlogbaf(n)T(n)=4T(n/2)+n2.a=4b=2f(n)=n2 and=nlog24=n2=Θ(nlogba)=Θ(n2)=Θ(n2lgn)

( 3 ) T ( n ) = 4 T ( n / 2 ) + n . a = 4 b = 2 f ( n ) = n 3   a n d n log ⁡ b a = n log ⁡ 2 4 = n 2 f ( n ) = Ω ( n log ⁡ b a + ϵ ) = Ω ( n log ⁡ 2 4 + ϵ ) \begin{aligned} (3) T(n)&=4T(n/2)+n. \quad a=4 \quad b=2 \quad f(n)=n^3 \ and \\ n^{\log_b^a}&=n^{\log_2^4}=n^2 \\ f(n)& =\Omega(n^{\log_b^{a+\epsilon}})=\Omega(n^{\log_2^{4+\epsilon}}) \end{aligned} (3)T(n)nlogbaf(n)=4T(n/2)+n.a=4b=2f(n)=n3 and=nlog24=n2=Ω(nlogba+ϵ)=Ω(nlog24+ϵ)
ϵ = 1 \epsilon=1 ϵ=1 对于足够大的n, a f ( n / b ) = 4 ( n / 2 ) 3 = n 3 / 2 = c f ( n ) af(n/b)=4(n/2)^3=n^3/2=cf(n) af(n/b)=4(n/2)3=n3/2=cf(n) 对于c=1/2成立,所以 T ( n ) = Θ ( n 3 ) T(n)=\Theta(n^3) T(n)=Θ(n3)

第四周作业–分治(上)

  1. 给定有序数组A以及一个元素x,设计一个寻找x的分治算法并分析其时间复杂度,要求返回x在数组中的位置。

算法思想:

  • 先将问题划分为大小近似相等的两个子问题
  • 对子问题递归调用该算法进行处理,递归出口为子问题只含一个元素,若该元素等于x,则返回x在数组中的位置
  • 由于给定数组是有序的,根据x的大小判断x位于哪个子问题,舍弃另一个子问题
A=[1,2,3,4,5,6,7,8,9]

def Search(A,left,right,x):
    if left>right:
        return 0
    
    mid = left+(right-left)//2
    if x ==A[mid]:
        return mid
    elif x<A[mid]:
        return Search(A,left,mid-1,x)
    else:
        return Search(A,mid+1,right,x)

Search(A,0,len(A),4)

T ( n ) = { Θ ( 1 ) n = 1 T ( n / 2 ) + Θ ( 1 ) n > 1 T(n)=\left\{ \begin{aligned} \Theta(1)\quad n=1 \\ T(n/2)+ \Theta(1) \quad n>1\\ \end{aligned} \right. T(n)={Θ(1)n=1T(n/2)+Θ(1)n>1
由公式法易得: T ( n ) = O ( l g n ) T(n)=O(lgn) T(n)=O(lgn)

2.给定n个整数的数组A以及一个数x,设计一个分治算法,求出x在数组中出现的次数,并分析时间复杂度。

算法思想:

  • 先将问题划分为大小近似相等的两个子问题
  • 对子问题递归调用该算法进行处理,递归出口为子问题只含一个元素,若该元素等于x,则返回x的出现次数为1,否则为0
  • 原问题结果为这两个子问题所得结果之和
A=[1,2,3,4,3,2,2,2,4,5,6]

def Count(A,left,right,x):
    if left == right:
        if A[left] == x:
            return 1
        else:
            return 0
    else:
        mid = left+(right-left)//2
        return Count(A,left,mid,x)+Count(A,mid+1,right,x)

Count(A,0,len(A)-1,4)

T ( n ) = { Θ ( 1 ) n = 1 2 T ( n / 2 ) + Θ ( 1 ) n > 1 T(n)=\left\{ \begin{aligned} \Theta(1)\quad n=1 \\ 2T(n/2)+ \Theta(1) \quad n>1\\ \end{aligned} \right. T(n)={Θ(1)n=12T(n/2)+Θ(1)n>1
由公式法易得: T ( n ) = Θ ( n ) T(n)= \Theta(n) T(n)=Θ(n)

第五周作业–分治(下)与动态规划(上)

  1. 说明怎样用L形板平铺任何没有方格缺失的2i3j平板,其中ij为正整数
    发现 i =1,j=1时,平板大小为2
    3,刚好可以被两个L形板平铺满。并且发现不论i,j的取值为多少,均能由大小为2*3的平板拼接而成。

  2. 机器人一次可以走1m,2m或3m。编写一个动态规划算法求机器人走n米有多少种走法?
    算法思想:
    设总路程为n米,共有f(n)种走法。易知f(1) = 1 f(2) = 2 f(3)=4,假设初值f(0) = 1
    可以求出递推式:f(n) = f(n - 1) + f(n - 2) + f(n - 3)
    递归求f(n)的方法:return f(n - 1) + f(n - 2) + f(n - 3)
    用动态规划求解:
    建立一个长度为3的数组,将每次运算的结果存进数组中,最后数组的和即为所求
    这样可以避免每次计算f(i)都要从f(0) + f(1) + f(2) 算起
    时间复杂度:Θ(n)
    空间复杂度:Θ(1)

def robotWalk(n):
    a=[1,1,2]
    if n <= 0:
        return 0
    elif n ==1:
        return a[1]
    elif n==2:
        return a[2]
    else:
        count = 0 
        for i in range(2,n):
            temp = a[2]+a[1]+a[0]
            a[count] = temp
            count = (count+1)%3
        return temp

robotWalk(4) # 7

第六周作业–动态规划(中)

  1. 请为DPLCSLength设计一个时间复杂度为O(MN)的备忘录算法
# 打印公共子序列
def PrintLcs(c,X,Y):
    i = len(X) # 行
    j = len(Y) # 列
    LcsLength = c[i][j] # 公共子序列长度
    LcsStr = [ ' ' for k in range(LcsLength)] # 存储公共序列
    
    while LcsLength > 0:
        if X[i-1] == Y[j-1]: # 回退到左上方
            LcsStr[LcsLength-1] = X[i-1]
#             print('loc',i,j,LcsLength)
            i -=1
            j -=1
            LcsLength -=1
        else: # 回退到上方或左边
            if c[i-1][j] >= c[i][j-1]:
                i -=1
            else:
                j -=1

    print(LcsStr)
        
# 寻找公共子序列
def LookupLcs(c,X,Y,i,j):
    if c[i][j] > -1:
        return c[i][j]
    if i==0 or j == 0:
        c[i][j] = 0
    else:
        if X[i-1] == Y[j-1]:
            c[i][j] = LookupLcs(c,X,Y,i-1,j-1)+1
        else:
            c[i][j] = max(LookupLcs(c,X,Y,i,j-1),LookupLcs(c,X,Y,i-1,j))
            
    return c[i][j]


def Lcs(X,Y):
    m = len(X)
    n = len(Y)
    c = [[-1 for j in range(n+1)]for i in range(m+1)]
    LookupLcs(c,X,Y,m,n)
    PrintLcs(c,X,Y)
    
X = 'ABCBDAB'
Y = 'BDCABA'
Lcs(X,Y) # BCBA
  1. 给定两个字符串A和B,以及下列三种字符运算:
    (1)删除一个字符(2)插入一个字符(3)将一个字符改写为另一个字符
    设计算法求将A通过以上三种操作转换为B的最小次数。

c [ i , j ] c[i,j] c[i,j]表示将 A i A_i Ai转换成 B j B_j Bj所需要的最小次数,则有三种情况:
删除A中一个字符,则 c [ i , j ] = c [ i − 1 , j ] + 1 c[i,j]=c[i-1,j]+1 c[i,j]=c[i1,j]+1
插入A中一个字符,则 c [ i , j ] = c [ i , j − 1 ] + 1 c[i,j]=c[i,j-1]+1 c[i,j]=c[i,j1]+1
改写A中一个字符,如果 A i = B j A_i=B_j Ai=Bj,则 c [ i , j ] = c [ i − 1 , j − 1 ] c[i,j]=c[i-1,j-1] c[i,j]=c[i1,j1],否则 A i = B j A_i=B_j Ai=Bj,则 c [ i , j ] = c [ i − 1 , j − 1 ] + 1 c[i,j]=c[i-1,j-1]+1 c[i,j]=c[i1,j1]+1

def minDistance(word1, word2):
    l1, l2 = len(word1) + 1, len(word2) + 1
    pre = [0 for _ in range(l2)]
    for j in range(l2):
        pre[j] = j
    for i in range(1, l1):
        cur = [i] * l2
        for j in range(1, l2):
            cur[j] = min(cur[j - 1] + 1, pre[j] + 1,
                         pre[j - 1] + (word1[i - 1] != word2[j - 1]))
        pre = cur[:]
    return pre[-1]

第七周作业–动态规划(下)

  1. 证明背包问题具有最优子结构性质
    最优子结构就是说:原问题的最优解包含子问题的最优解。在背包问题中,我们假设 ( X 1 , X 2 , ⋯   , X n ) (X_1,X_2,\cdots,X_n) (X1,X2,,Xn)是背包问题的最优解,则 ( X 2 , ⋯   , X n ) (X_2,\cdots,X_n) (X2,,Xn)是其子问题的最优解。
    反证法,假设 ( Y 2 , ⋯   , Y n ) (Y_2,\cdots,Y_n) (Y2,,Yn)是上述问题的子问题的最优解,则有 ( Y 2 V 2 , ⋯   , Y n V n ) + V 1 X 1 > ( X 2 V 2 , ⋯   , X n V n ) + V 1 X 1 (Y_2V_2,\cdots,Y_nV_n)+V_1X_1>(X_2V_2,\cdots,X_nV_n)+V_1X_1 (Y2V2,,YnVn)+V1X1>(X2V2,,XnVn)+V1X1,也就是说 ( X 1 , Y 2 , ⋯   , Y n ) (X_1,Y_2,\cdots,Y_n) (X1,Y2,,Yn)是背包问题的最优解,与最开始的假设" ( X 1 , X 2 , ⋯   , X n ) (X_1,X_2,\cdots,X_n) (X1,X2,,Xn)是背包问题的最优解"矛盾,所以背包问题具有最优子结构性质

  2. 假设海岸线为一条直线,陆地在海平面一边有很多小岛,每个小岛可视为一个点。海岸上可布控多个雷达,每个雷达监测半径为d,若小岛到雷达的范围不超过d,那么小岛就在雷达可控范围内,如附件所示,x轴为海岸,海位于x轴上方,小岛坐标为(x,y)。给定一些小岛的坐标和雷达控制范围d,设计算法计算控制所有小岛所需的雷达数目。
    在这里插入图片描述

import math

data = [[1,2],[-3,1],[2,1]] # 小岛坐标
d  = 2.0 # 雷达半径
 
# 考虑每个小岛被覆盖所需雷达的范围,排序线段 
def solution(data,d):
    n = len(data) # 小岛数量
    s = [[0 for col in range(2)] for row in range(n)] # 保存雷达范围
    
    for  i in range(n):
        if data[i][1]>d: # 判断是否所有小岛都能被覆盖
            return -1
        else:
            # 将小岛坐标转化为雷达覆盖线段
            L = math.sqrt(d**2-data[i][1]**2)
            s[i][0]=data[i][0]-L # left
            s[i][1]=data[i][0]+L # right
    
    
    s = sorted(s,key=lambda xy:xy[0]) # 按左端点从小到大排序
    ans =1
    res = s[0][1] # 保存集合右端点的最小值
    for i in range(n):
        # 新加入线段的左端点是否大于当前结合右端点的最小值
        if s[i][0]<=res: # 有公共交点,更新右端点的最小值
            res = min(s[i][1],res)
        else: # 建立新雷达
            ans +=1
            res = s[i][1]
    return ans
    
solution(data,d) # 2

第八周作业–贪心算法

  1. 假设你有一个数组,其中第i 个元素是第i天给定股票的价格。设计算法以找到最大利润。你可以根据需要完成尽可能多的交易(即,多次买入并卖出一股股票)。注意:您不能同时进行多笔交易(即,您必须在再次购买之前卖出股票)
    例如:给定数组[7,1,5,3,6,4],算法输出:7
    说明:第二天买入(价格:1)第三天卖出(价格:5)利润:5-1=4,然后第四天买入(价格:3)并在第五天卖出(价格:6),利润6-3=3,总利润:4+3=7
    要求给出测试案例,设计算法,并给出算法在你的测试案例上计算得到的结果。
def maxProfit(prices):
    if not prices:
        return 0
    
    res = 0
    for i in range(1,len(prices)):
        if prices[i]>prices[i-1]:
            res += (prices[i]-prices[i-1])
    
    return res

prices1 = [7,1,5,3,6,4]
print(maxProfit(prices1)) # 7

prices2 = [1,2,3,4,5,6] # 5
print(maxProfit(prices2))
  1. 根据任务选择问题的递推表达式,设计动态规划算法。
s = [float("-inf"),1,3,0,5,3,5,6,8,8,2,12,float("inf")]
f = [0,4,5,6,7,8,9,10,11,12,13,14,float("inf")+1]

def task(s,f):
    n = len(s)
    c  = [[0 for i in range(n)] for j in range(n)]
    for i in range(n):
        for j in range(i+1,n):
            max_value = -1
            for k in range(i+1,j):
                # print('i:',i,'j: ',j,'k ',k)
                if s[k]>=f[i] and f[k]<=s[j]:
                    max_value = c[i][k]+c[k][j]+1
                    c[i][j] = max(c[i][j],max_value)
    return c[0][n-1]
    
task(s,f)  # 4

第九周作业–图算法(上)

  1. 重写DFS算法,用栈来消除递归
def DFS_stack(G,s):# s指的是开始结点
    stack=[]
    stack.append(s)
    seen=set() # 记录是否访问过
    seen.add(s)
    while (len(stack)>0):
        vertex=stack.pop() # 最后一个元素
        nodes=G[vertex] # 相邻点
        for w in nodes:
            if w not in seen:# 未访问过
                stack.append(w)
                seen.add(w)
  1. 给定图G(V,E),以及其对应的一棵最小生成树,假定减少图中不属于最小生成树的一条边的权重,设计算法找出修改边后新图的最小生成树
  • 把修改后的边加入到最小生成树里,形成一条含修改边的回路,去除这个回路中权值最大的边,就可以得到一颗新的最小生成树
#Kruskal算法
def Kruskal(graph):
    vnum=graph.vertex_num()
    reps=[i for i in range(vnum)]
    mst,edges=[],[]
    for vi in range(vnum):
        for v,w in graph.out_edges(vi):
            edges.append((w,vi,v))
	# 对所有边进行排序
    edges.sort()
    for w,vi,vj in edges:
        if reps[vi]!=reps[vj]:
        	# 保存最小生成树
            mst.append(((vi,vj),w))
            if len(mst)==vnum-1:
                break
            rep,orep=reps[vi],reps[vj]
            for i in range(vnum):
                if reps[i]==orep:
                    reps[i]=rep
    return mst

# 得到最小生成树
mst = Kruskal(graph)
# 设被减少的边的权重是w12,端点是v1,v2
mst.append(((v1,v2),w12))
# 按照权重排序
mst.sort(key=lambda x:x[-1])
# 去除权重最大的边
mst.pop(-1)

第十周作业–图算法(下)

  1. 如何利用Floyd-WarShall算法检测负权回路的存在

继续迭代Floyd-WarShall算法,检查d值的变化。如果有负权回路,则某些最短路径的权和会变小;如果没有负权回路,则d值不会发生改变。

  1. 下图为Dijkstra算法的伪代码:
    在这里插入图片描述

将Dijkstra算法第四行改为:
while |Q|>1
使得while循环执行|V|-1次而不是|V|次,算法是否仍然正确?

算法正确,令u是队列Q中剩余的顶点。如果u不能从s可达,则有 d [ u ] = δ ( s , u ) = ∞ d[u]=\delta(s,u)=\infty d[u]=δ(s,u)=。如果u从s可达,则有一条路径p,它从s经过x再直接到u, d [ x ] = δ ( s , x ) d[x]=\delta(s,x) d[x]=δ(s,x),按照最短路径松弛性质,可得 d [ u ] = δ ( s , u ) d[u]=\delta(s,u) d[u]=δ(s,u),故算法正确

第十一周作业–网络流与匹配

  1. 求以下网络最大流,给出求解过程
    在这里插入图片描述
    第一步:我们把每条边的的信息用残量 / 容量表示出来,第一次找到的增广路为S-1-2-T,我们把这条路径上的边的 w(u,v) 减去 min{f(u,v)} 即 15,同时把反向边都增加15
    第二步:找到路径S-3-T,剩余最大流量是19,正向边减19,反向边加19
    第三步:找到路径S-1-4-3-T,剩余最大流量是6,正向边减6,反向边加6
    第四步:找到S-4-3-T,剩余最大流量是6,正向边减6,反向边加6

网络中没有增广路了,最大流量为:15+19+6+6=46

在这里插入图片描述
2. 求以下网络节点1到节点6的最大流
在这里插入图片描述

第一步:我们把每条边的的信息用残量 / 容量表示出来,第一次找到的增广路为1-3-5-6,我们把这条路径上的边的 w(u,v) 减去 min{f(u,v)} 即 10,同时把反向边都增加10
第二步:找到路径1-2-5-6,剩余最大流量是6,正向边减6,反向边加6
第三步:找到路径1-4-6,剩余最大流量是5,正向边减5,反向边加5
第四步:找到1-4-3-5-6,剩余最大流量是1,正向边减1,反向边加1
第五步:找到1-4-2-5-6,剩余最大流量是1,正向边减1,反向边加1

网络中没有增广路了,最大流量为:10+6+5+1+1=23

在这里插入图片描述

第十二周作业–NP完全理论

  1. 解释什么是N问题,什么是NP问题
  • P:多项式时间可解的具体判定问题的集合。
  • NP:一类能够被多项式时间验证算法所验证语言的集合。
  1. 证明如下问题是NP-完全的:
    输入:两个图G1 = (V1, E1) 和G2 = (V2, E2) :预算b。
    输出:两个节点集合V1’∈ V1 和V2’∈ V2和它们被移除后,将在两图中分别留下至少b个节点,且图的剩余部分完全一样

NPC问题的需要同时满足下面两个条件:① 首先,它是一个 NP 问题;②然后,所有的 NP 问题都可以在多项式时间内归约到它。即如果所有 NP 问题都能在多项式时间内归约到一个 NP 问题,则称该 NP 问题为 NP 完全问题。

证明:
首先我们给定两个图G1=(V,E),G2=(V,∅),其中两个图的顶点集是相同的,但是第二个图的边集为空,我们求这两个图的节点数至少为b的最大公共子图。规约的证明如下:

(1)如果上述两个图存在节点数为b的最大公共子图,那么这b个节点就是图的独立集。利用反证法,假如这b个节点不是独立集,也就是说其中两个节点有边相连,那么在G1的子图中这两点之间必然有边相连,但是G2中边集为空,也就是说这两点没有边相连,与它们是公共子图矛盾,所以只要上述两个图存在节点数为b的最大公共子图,那么这b个节点就是图的独立集。

(2)如果G1有节点数为b的独立集,那么只要G1和G2都只取这b个点作为它们的子图,由于G1中各个点之间都没有边相连,否则它们就不是独立集,而G2中本来边集就为空,所以两个子图都只要b个点而没有边,显然这两个子图是完全相同的,也就是说这两个图也有节点数为b的公共子图。

从上述证明可以知道,求图的独立集问题是可以规约到求最大公共子图问题上的,所以最大公共子图问题也是NP完全问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值