zoukankan      html  css  js  c++  java
  • 【codevs1036】商务旅行 LCA 倍增

    1036 商务旅行

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 钻石 Diamond
    题目描述 Description

    某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。

    假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。

    你的任务是帮助该商人计算一下他的最短旅行时间。

    输入描述 Input Description

    输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=ab<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。

    输出描述 Output Description

        在输出文件中输出该商人旅行的最短时间。

    样例输入 Sample Input
    5
    1 2
    1 5
    3 5
    4 5
    4
    1
    3
    2
    5
    样例输出 Sample Output

    7


    题解:
      这道题主要是用来巩固lca和倍增算法的,是一道模板题。一个简单的树上倍增,找最近公共祖先。注意局部ans的细节处理,不是对整体相乘,而是对当前步数乘以2。然后借鉴了网上的博客的另一种计算方法:用depth来计算。写第一遍时又把倍增递推写错了。。注意数组开两倍。。
    我的方法:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define maxn 30005
     6 using namespace std;
     7 int n,m,city[maxn],ans,fist;
     8 int tot,he[maxn],to[maxn*2],ne[maxn*2];
     9 bool flag[maxn];
    10 int f[14][maxn],depth[maxn];
    11 void add(int a,int b)
    12 {
    13     tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot;
    14 }
    15 void build (int x)
    16 {
    17     for (int i=he[x];i;i=ne[i])
    18     if (!flag[to[i]]){
    19         flag[to[i]]=true;
    20         depth[to[i]]=depth[x]+1;
    21         f[0][to[i]]=x;
    22         build(to[i]);
    23     }    
    24 }
    25 void bz()
    26 {
    27     for (int i=1;i<=12;i++) 
    28       for (int j=1;j<=n;j++)
    29          f[i][j]=f[i-1][f[i-1][j]];
    30 }
    31 int lca(int a,int b)
    32 {
    33     int mi=0;
    34     if (depth[a]<depth[b]) swap(a,b);
    35     int derta=depth[a]-depth[b];
    36     for (int i=0;i<=12;i++)
    37     {
    38         if (1<<i & derta)
    39         {
    40             mi+=(1<<i);
    41             a=f[i][a];    
    42         }
    43     }
    44     if (a==b) return mi;
    45     for (int i=12;i>=0;i--)
    46     {
    47         if (f[i][a]!=f[i][b]) {
    48             a=f[i][a];
    49             b=f[i][b];
    50             int p=(1<<i);p*=2;//not mi+=(1<<i);mi*=2;
    51             mi+=p;
    52         }
    53     }
    54     a=f[0][a];b=f[0][b];
    55     mi+=2;
    56     return mi;
    57 }
    58 int main()
    59 {
    60     freopen("codevs1036.in","r",stdin);
    61     cin>>n;
    62     for (int i=1;i<n;i++)
    63     {
    64         int x,y;
    65         scanf("%d%d",&x,&y);
    66         add(x,y);
    67         add(y,x);
    68     }
    69     flag[1]=true;
    70     depth[1]=1;
    71     build(1);
    72     bz();
    73     cin>>m;cin>>fist;
    74     for (int i=1;i<m;i++)
    75     {
    76         int x;scanf("%d",&x);
    77         int y=lca(fist,x);
    78         ans+=y;
    79         fist=x;
    80     }
    81     cout<<ans<<endl;
    82     return 0;
    83 }
    View Code

    借鉴方法:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define maxn 30005
     6 using namespace std;
     7 int n,m,city[maxn],ans,fist;
     8 int tot,he[maxn],to[maxn*2],ne[maxn*2];
     9 bool flag[maxn];
    10 int f[14][maxn],depth[maxn];
    11 void add(int a,int b)
    12 {
    13     tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot;
    14 }
    15 void build (int x)
    16 {
    17     for (int i=he[x];i;i=ne[i])
    18     if (!flag[to[i]]){
    19         flag[to[i]]=true;
    20         depth[to[i]]=depth[x]+1;
    21         f[0][to[i]]=x;
    22         build(to[i]);
    23     }    
    24 }
    25 void bz()
    26 {
    27     for (int i=1;i<=12;i++) 
    28       for (int j=1;j<=n;j++)
    29          f[i][j]=f[i-1][f[i-1][j]];
    30 }
    31 int lca(int a,int b)
    32 {
    33     //int mi=0;
    34     if (depth[a]<depth[b]) swap(a,b);
    35     int derta=depth[a]-depth[b];
    36     for (int i=0;i<=12;i++)
    37     {
    38         if (1<<i & derta)
    39         {
    40             //mi+=(1<<i);
    41             a=f[i][a];    
    42         }
    43     }
    44     if (a==b) return a;
    45     for (int i=12;i>=0;i--)
    46     {
    47         if (f[i][a]==f[i][b]) continue;
    48         else {
    49             a=f[i][a];
    50             b=f[i][b];
    51         //    mi+=(1<<i);mi=(mi<<1);
    52         }
    53     }
    54 //    a=f[0][a];b=f[0][b];
    55     //mi+=2;
    56     return f[0][a];
    57 }
    58 int main()
    59 {
    60     freopen("codevs1036.in","r",stdin);
    61     cin>>n;
    62     for (int i=1;i<n;i++)
    63     {
    64         int x,y;
    65         scanf("%d%d",&x,&y);
    66         add(x,y);
    67         add(y,x);
    68     }
    69     flag[1]=true;
    70     depth[1]=1;
    71     build(1);
    72     bz();
    73     cin>>m;cin>>fist;
    74     for (int i=1;i<m;i++)
    75     {
    76         int x;scanf("%d",&x);
    77         ans+=depth[fist]+depth[x]-2*depth[lca(fist,x)];
    78         fist=x;
    79     }
    80     cout<<ans<<endl;
    81     return 0;
    82 }
    View Code
  • 相关阅读:
    java 9+版本中,接口的内容总结
    发红包的案例
    java中成员变量和局部变量的区别
    分别使用面向对象和面向过程两个不同的思路编写代码,打印输出一个数组,输出数组的格式:“[10,20,30,40,50]”
    题目要求:不能使用新数组,就用原来的唯一的数组进行反转
    request.getRequestDispatcher()和response.sendRedirect()区别
    Maven是什么
    字符串中的各种方法
    数组中的各种方法
    字符串的模式匹配方法-match-search-repalce
  • 原文地址:https://www.cnblogs.com/lx0319/p/5971074.html
Copyright © 2011-2022 走看看