• 生成树相关问题


    算法竞赛入门经典训练指南

    第5章 图论算法与模型

    5.4 生成树相关问题

    例题21 bond UVa11354

    有n座城市通过m条双向道路相连,每条道路有一个危险系数。你的任务是回答若干个询问,每个询问包含一个起点s和一个终点t,要求找到一条s到t的路,使得路径所有边的最大危险系数最小。

    相似的题

    noip 2013 day1 truck

    【分析】本题也是要求瓶颈路,但需要快速回答很多查询。这很像前面数据结构部分的题目,因此也可考虑先做预处理,把信息组织成某种易于查询的结构。

    首先求出最小生成树,并把它改写成有根树,让fa[i]和cost[i]分别节点i的父亲编号和它与父亲之间的边权,L[i]表示节点i的深度(根节点的深度为0,根节点的子节点深度为1,以此类推)。

    无根树转有根树的代码如下。

     1 class SetRoot{
     2 public:
     3     static void pretreat(vector<edge *> & T,vector<int> * G){
     4         for(int i=0;i<T.size();i++){
     5             edge & e=*T[i];
     6             G[e.v1].push_back(i);
     7         }
     8     }
     9     static void dfs(vector<edge *> & T,vector<int> * G,int * fa,int u,int fthr){
    10         vector<int> & g=G[u];
    11         for(int i=0;i<g.size();i++){
    12             edge & e=*T[g[i]];
    13             if(e.v2!=fa)dfs(T,G,fa,e.v2,p[e.v2]=u);
    14         }
    15     }
    16 };

    接下来通过预处理计算出anc数组和maxcost数组,其中anc[i][j]表示节点i的第2级祖先编号(anc[i][0]就是fa[i],anc[i][j]=-1表示该祖先不存在),maxcost[i][j]表示节点i和它的2j级祖先之间路径上的最大值。预处理代码如下。

     1 void prepoccess(){
     2     for(int i=0;i<n;i++){
     3         anc[i][0]=fa[i];maxcost[i][0]=cost[i];
     4         for(int j=1;(1<<j)<n;j++)anc[i][j]=-1;
     5         }
     6     for(int j=1;(1<<j)<n;j++)
     7         for(int i=0;i<n;i++)
     8             if(anc[i][j-1]!=-1){
     9                 int a=anc[i][j-1];
    10                 anc[i][j]=anc[a][j-1];
    11                 maxcost[i][j]=max(maxcost[i][j-1],maxcost[a][j-1]);
    12             }
    13  }   

     有了这些预处理我们就可以编写查询处理过程了。假定查询的两个节点为p和q,并且p比q深(如果不是的话,交换),则可以先把p提升到和q同一级的位置,然后用类似二进制展开的方法不断把p和q同时往上“提”(要保证二者深度始终相等),同时更新最大边权。代码如下。

    int query(int p,int q){
        int tmp;int log=0;if(L[p]<L[q])swap(p,q);
        while((1<<(log+1))<=L[p])log++;int ans=-INF;
        for(int i=log;i>=0;i--)
            if(L[p]-(1<<i)>=L[q]){
                ans=max(ans,maxcost[p][i]);
                p=anc[p][i];
            }
        if(p==q)return ans;//LCA(p,q)=p
        for(int i=log;i>=0;i--)
            if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
                ans=max(ans,maxcost[p][i]);
                p=anc[p][i];
                ans=max(ans,maxcost[q][i]);
                q=anc[q][i];
            }
        
        ans=max(ans,cost[p]);
        ans=max(ans,cost[q]);
        return ans;//LCA(p,q)=fa[p]=fa[q];
    }

     上述代码也能求出p和q的最近公共祖先(见注释)。这样,就在预处理O(nlogn),和查询O(logn)的时间内解决了本题。

  • 相关阅读:
    Beta版软件说明书
    团队项目第五天
    cnblogs用户体验评价
    团队项目测试计划
    Alpha版总结会议
    软件使用说明书
    团队绩效考核
    各个小组对于“我爱淘”的评价
    软件工程团队项目评价
    丹佛机场行李系统处理方案
  • 原文地址:https://www.cnblogs.com/JebediahKerman/p/5678625.html
Copyright © 2020-2023  润新知