《算法导论》笔记(14) 基本的图算法 部分习题

习题22.1-5 有向图G(V, E)的平方图。链表表示时,对每结点u的Adj[u]中所有v加入队列,后边出队边将Adj[v]加入Adj[u]中。矩阵表示时,若w[i, j]、w[j, k]同时为1则将w[i, k]置1.

习题22.1-6 O(V)的时间寻找通用汇点。汇点的特征是邻接矩阵的第j列除[j, j]外所有元素为1. 可将每行调整[j ,j]后作为一个整数,所有整数与运算,为1的位是汇点。

习题22.1-7 有向无环图的关联矩阵B,BB'每个元素C[i, j]=∑B[i, k]*B'[k, j]=∑B[i, k]*B[j, k],即同时进i, j两结点与同时出i, j的结点总数-一进一出i, j两结点的结点总数。

习题22.2-7 类似BFS,d mod2为0则标为B(娃娃脸),d mod2为1则标为H(高跟鞋)。但若有边连接相同类的结点,则无法划分。

wrestler(G){
  for each u in G{
    (u,v)=Adj[u]; 
    if(v.mark==u.mark){throw error;}
    if(v.d==NIL) {v.d=u.d+1; v.mark=v.d mod 2;}
  }
}

习题22.2-8 任意点之间的最短路径。重复的Dijktra算法或Floyd-Warshall算法

习题22.2-9 无向图扩展为有向图。问题变成要遍历所有边一次。访问结点u时,将u的子结点v的其他边都可视为子集v,问题等价于u到v,访问v的集合,v到u。u标为visiting入列,然后访问v,v标为visiting入列,然后访问v的后继结点,访问过的边标为visited,返回到visiting的点时,如果该点所有连接的边都标为visited只剩一条返回上级的边,则返回上级结点并将点标为visited,v出列,访问u的其他子结点,最终u出列。全部结点出列后达到遍历所有边一次。

expand all (u, v) to (v, u);
visit_all_paths(G){
  Q.push(u0);
  while(Q not full){
    u=Q.pop(); visit(u);
  }
}
visit(u){
  for each (u, v) in Adj[u]{
    if((u, v) not visited){
      if(v not visiting){
        mark v as visiting; v.p=u; Q.push(v);
        mark (u, v) as visited; visit(v); 
      }
      if(v is visiting){mark (u, v) as visited; mark (v, u) as visited;}
    } 
  }
  mark u as visited; Q.pop();
}
习题22.3-7 重写DFS算法,用栈代替递归。

DFS(G){
  for each vertex u in G.V{
    while(u not visited){
      if(u not visiting) {mark u as visiting; insert all Adj[u] to stack[u];}
      if(stack[u] not empty){
        v=stack[u].pop();
        if(v neither visited nor visiting) {v.p=u; u=v; continue;}
      }
      else {mark u as visited; if(u.p not null) u=u.p;}
    }
  }
}

习题22.3-13 判断有向图是否单连通图。访问到已标记为visited的结点时,回溯到根结点,检查有无公共的根结点。

习题22.4-2 拓扑排序后,从起点开始计数,s有边连接的点,路径为1,然后向后推导,某点v路径数为v的所有入边(u,v)的前驱点u的路径相加。从s到t,得到路径数量。

习题22.4-5 可以用邻接矩阵w,入度为0的点,其列上元素无1,其行上元素无-1, 删掉一个点后,删去其行及其列。但若有环,无法拓扑排序。

习题22.5-6 首先,各强连通分量收缩为一个点,然后将这些点之间的边删除。然后对每个连通分量去掉出入度大于1的点的多余边。获得最少|V|的G'。

习题22.5-7 半连通问题。如果能够任意两点之间至少有一条路径到达,那么可以知道,一种无回溯的DFS遍历必然能到达所有点。反证法:若不能遍历,那么必有两点u到v之间无路径。

semi_connected_components(G){
  while(count <= |V| ) {    
    if(u not visiting) {mark u as visiting; push each Adj[u] in stack[u]; count++;}
    if(stack[u] not empty) {v=stack[u].pop(); u=v; continue;}
    else {mark u as visited; break;}
  }
  if(count!=|V|) throw error;
}

思考题22-3 欧拉回路。1,v=Adj[u].pop()的方式寻找一个回路。每个路过的元素作为一个循环链表的结点。每个路过的结点in_degree与out_degree各-1,若有degree不等于0的,将其用递归方法展开,即从该结点开始寻找另一个子回路,并将子回路经过的路径再次加入循环链表的相应位置。如此直到所有边都被加入为止。

思考题22-4 从L标记为1点开始,按照BFS遍历,并更新可到达点的值。记录拥有最新min(R)=1元素个数i,那么下一次从L标记i+1个结点开始,BFS遍历。如此类推。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值