• Codevs 1036 商务旅行


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

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

    假设有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

     1 #include<cstring>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<iostream>
     5 using namespace std;
     6 #define maxn 30010
     7 #define S 16
     8 int n,m,a[30010],deep[30010],fa[maxn][S+10],ans,p1,p2,head[30010],num;
     9 
    10 struct node{
    11     int u,v,pre;
    12 }e[maxn*2];
    13 void dfs(int now,int from,int deepth)
    14 {
    15     fa[now][0]=from;
    16     deep[now]=deepth;
    17     for(int i=head[now];i;i=e[i].pre)
    18       if(e[i].v!=from)
    19         dfs(e[i].v,now,deepth+1);
    20 }
    21 void get_fa()
    22 {
    23     for(int j=1;j<=S;j++)
    24         for(int i=1;i<=n;i++)
    25             fa[i][j]=fa[fa[i][j-1]][j-1];
    26 }
    27 int LCA(int a,int b)
    28 {
    29     if(deep[a]<deep[b])swap(a,b); 
    30     for(int j=S;j>=0;j--)
    31       if((deep[a]-(1<<j))>=deep[b])
    32         a=fa[a][j];
    33     if(a==b)return a;
    34     for(int i=S;i>=0;i--)
    35       if(fa[a][i]!=fa[b][i])
    36         {
    37           a=fa[a][i];
    38           b=fa[b][i];
    39         }
    40     return fa[a][0];
    41 }
    42 void add_egre(int from,int to)
    43 {
    44     num++;
    45     e[num].u=from;
    46     e[num].v=to;
    47     e[num].pre=head[from];
    48     head[from]=num;
    49 }
    50 int main()
    51 {
    52     scanf("%d",&n);
    53     for(int i=1,x,y;i<n;i++)
    54     {
    55         scanf("%d%d",&x,&y);
    56         add_egre(x,y);add_egre(y,x);
    57     }
    58     scanf("%d%d",&m,&p1);
    59     memset(deep,0,sizeof(deep));
    60     dfs(1,1,0);
    61     get_fa();
    62     for(int i=1;i<=m-1;i++)
    63     {
    64         scanf("%d",&p2);
    65         int k=LCA(p1,p2);
    66         ans+=deep[p1]+deep[p2]-2*deep[k];// deep 该点的深度
    67         p1=p2;
    68     }
    69     printf("%d
    ",ans);
    70     return 0;
    71 }

    思路:树上任意两点间的最短距离等于deep[p1]+deep[p2]-2*deep[p1,p2的最近公共祖先]

  • 相关阅读:
    套接字I/O模型-WSAAsyncSelect
    套接字I/O模型-完成端口IOCP
    套接字I/O模型-WSAEventSelect(转载)
    Win7+VS2010环境下CEGUI 0.8.4编译过程详解
    数组去重统计排序
    计算当前月有几天
    前端开发仓库
    Jquery中bind(), live(), on(), delegate()四种注册事件的优缺点,建议使用on()
    图表那些事
    图标字体,矢量图标
  • 原文地址:https://www.cnblogs.com/suishiguang/p/6103601.html
Copyright © 2020-2023  润新知