距离上次更新已经 1488 天了,文章内容可能已经过时。

课程主页:

https://cs170.org/

https://inst.eecs.berkeley.edu/~cs170/fa18/

课程视频:

https://www.bilibili.com/video/BV1wK411g7ck

这次回顾Hw3。

2. Disrupting a Network of Spies

(a)
f(r)=r

假设r的子节点为ri,i=1,,l,那么只要说明ij,不存在ri的后代到rj的后代的路径即可。

证明:

如果存在ri的后代rirj的后代rj的路径,那么rj必然是ri的后代,这就与rjrj的后代矛盾,所以结论成立。

(b)

假设v的子节点为{vi},父节点为vp,现在对树进行旋转,以v为根节点,子节点为{vi}{vp}

由条件可得,不存在{vi}及其后代到vp及其后代的横跨边,所以这是一棵合理的搜索树,因此

f(r)=r+1
(c)

注意到如果存在和v的后代相关的回边,那么回边的另一个节点必然在v到根节点的路径上,否则会产生矛盾(类似a中讨论)。

和(c)类似,依然是使用旋转的方式,所以只要判断是否会增加1即可,而这和v的后代的邻居是是否在搜索树中的深度小于v有关,具体如下:

f(r)=r+1[[i=1kupT(wi)<depthT(v)]]
(d)

注意到

upT(u)=min(minvuupT(v),min(u,v)EdepthT(v))

以及如果u是叶节点(注意此时u没有后代),那么

upT(u)=min(u,v)EdepthT(v)

所以可以分两轮计算up

  • 层序遍历计算depth

  • initUp():

    • 初始化upT(u)=depthT(u)

    • for (u,v)E:

      • upT(u)=min(upT(u),depthT(v))upT(v)=min(upT(v),depthT(u))
    • getUp(u):

      • 如果u是叶节点,

        • continue
      • 否则,

        • for v in u的子节点:

          • getUp(v)
        • upT(u)=minvuupT(v)
    • initUp()

    • getUp(root)

时间复杂度:

  • 层序遍历:O(|V|+|E|)

  • initUp(),getUp(root)对每个节点和边各遍历一次,所以时间复杂度为O(|V|+|E|)

(e)
  • 初始化f[n]={0}
  • 选择节点r,对v调用dfs得到搜索树T时间复杂度O(|V|+|E|)
  • f[r]=r的子节点个数。
  • 利用(d)部分的算法计算其余f[v],这步时间复杂度为O(|V|+|E|)

总时间复杂度为O(|V|+|E|)

3. Inverse FFT

(a)

记矩阵M的第i行为M[i,:],第j列为M[:,j],那么

Mn(ω)[:,j]=[1ωjω2jω(n1)j]TMn(ω1)[i,:]=[1ωiω2jω(n1)j]

那么

Mn(ω1)[i,:]Mn(ω)[:,j]=k=0n1ωk(ji)={ni=j1ωn(ji)1ω=0ij

注意到

1nMn(ω1)Mn(ω)=1n[Mn(ω1)[i,:]Mn(ω)[:,j]]n×n

因此

1nMn(ω)Mn(ω)=In
(b)
Mn(ω)[i,j]=ω(i1)(j1)Mn(ω1)[i,j]=ω(i1)(j1)

那么

Mn(ω)[i,j]=ω(j1)(i1)=Mn(ω1)[i,j]1nMn(ω)1nMn(ω)=1nMn(ω)Mn(ω1)=In

结论成立。

(c)

由多项式的定义可得

[C(1)C(ω)C(ωn1)]=[11111ωω2ωn11ωn1ω2(n1)ω(n1)(n1)][c0c1cn1]=Mn(w)[c0c1cn1][c0c1cn1]=Mn1(w)[C(1)C(ω)C(ωn1)]=1nMn(ω1)[C(1)C(ω)C(ωn1)]
(d)

推导同课程笔记,只要将ω替换为ω1即可:

https://doraemonzzz.com/2021/02/21/%E7%AE%97%E6%B3%95%E6%A6%82%E8%AE%BA(DPV)%E7%AC%AC2%E7%AB%A0%20%E5%88%86%E6%B2%BB%E7%AE%97%E6%B3%95%20%E6%80%BB%E7%BB%93/#toc-heading-9第2章 分治算法 总结/#toc-heading-9)

4. Vandermonde matrix

(a)

注意到

[p(0)p(1)p(4)p(7)]=V4(0,1,4,7)[1201]=[100011111416641749343][1201]=[1473358]
(b)
[p(0)p(1)p(4)p(7)]=V4(0,1,4,7)[p0p1p2p3]=[100011111416641749343][p0p1p2p3][p0p1p2p3]=[100011111416641749343]1[p(0)p(1)p(4)p(7)]=[100011111416641749343]1[20630]=[2310]

所以

q(x)=x23x+2
(c)

xi=wi1

5. Connectivity vs Strong Connectivity

(a)

因为是连通图,所以DFS得到一颗搜索树,那么删除搜索树任意叶节点即可。

(b)
Code
a -> b -> c -> d -> a

那么删除任意一个节点都不够成强连通图。

(c)

反证法,如果存在节点对u,v,(u,v)E,只有一条uv路径,考虑uv路径中一点v0,那么删除该节点后,不存在uv路径,于是图不连通,这就与假设矛盾。

6. Finding Clusters

  • 初始化m[n]={0}

  • 计算(V,E)的SCC,得到每个节点的强连通分量编号a[n]以及图元(V1,E1),图元的节点数量为m,初始化

    m[i]=m1[j]=min{j|a[i]=j}j=1,,m
  • 线性化图元,顺序为i1,,im

  • for j=m,,1

    • m1[ij]=minijkm1[k]
  • for i=1,,n

    • m[i]=m1[a[i]]

时间复杂度:

  • 计算(V,E)的SCC:O(|V|+|E|)
  • 线性化图元:O(|V1|+|E1|)
  • 循环1:每个节点和每个边各访问一次,O(|V1|+|E1|)
  • 循环2:O(|V|)

所以时间复杂度为

O(|V|+|E|)

7. Arbitrage

(a)

i,j之间边的权重为logri,j,所以我们的目标是找到路径st,使得

minimizej=0n1logrij,ij+1,i0=s,in=t
(b)

可以转化为单源最短路径问题,利用Bellman-Ford算法即可。

8. Bounded Bellman-Ford

返回Bellman-Ford算法的第i轮循环结果:

  • procedure update((u,v)E)
    • dist(v)=min{dist(v),dist(u)+l(u,v)}

BF

  • procedure shortest-paths(G,l,s,k)
  • for all uV:
    • dist(u)=
    • prev(u)=nil
  • dist(s)=0
  • repeat k times:
    • for all eE:
      • update(e)

解释:

考虑最短路径树,那么BF算法第i轮计算出第i层的最短距离,这点利用数学归纳法即可证明。

9. Matrix Filling

将第i列视为一个节点,那么节点为1,2,,n,考虑如下算法:

  • 选择未访问的节点i,j

  • 合并vi,vj,当且仅当存在k,使得vi[k]并且vj[k],记

    α=vi[k]vj[k]
  • for k=1,,n

    • 如果vj[k]
      • 如果vi[k]=
        • vi[k]=αvj[k]
      • 如果vi[k]αvj[k]
        • return false
    • 如果vi[k]
      • 如果vj[k]=
        • vj[k]=vi[k]/α
      • 如果vj[k]vi[k]/α
        • return false
  • 标记j为访问过。

重复上述操作,最后剩下k个节点i1,,ik,这些节点满足,任取stvis[k],vit[k]不同时为值,即满足类似如下形式:

Code
000111000
110000001
001000010
......
111111011

上图中,标记为0的地方表示该位置的值为,标记为1的地方表示填了值,最后为合并后的结果,剩余为的地方可以填任意值,完成后,根据比例在矩阵中填值即可。

时间复杂度:

每次合并的时间复杂度为O(n),最多合并n1次,最后处理的时间复杂度为O(kn),所以总的时间复杂度为O(n2)