码迷,mamicode.com
首页 > 其他好文 > 详细

商务旅行

时间:2018-08-04 21:37:22      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:lin   ext   rand   one   and   pad   wrap   eof   分享图片   

商务旅行

 

时间限制: 1 s
空间限制: 128000 KB 

 
题目描述 Description

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

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

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

输入描述 Input Description

输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数ab (1<=a, b<=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)的裸题,mark一下lca的写法。
技术分享图片
#include<iostream>
#include<vector>
#include<cmath>
#include<cstring>
#include<cstdio>
#define N 100005
using namespace std;

struct edge{int v,w;};
vector<edge>edges[N];
int grand[N][25]={0},gw[N][25]={0};
int depth[N],DEPTH,n;

void addedge(int a,int b,int w)
{
    edges[a].push_back((edge){b,w});
    edges[b].push_back((edge){a,w});
}

void dfs(int x)
{
    for(int i=1;i<=DEPTH;i++)
    {
        grand[x][i]=grand[grand[x][i-1]][i-1];
        gw[x][i]=gw[x][i-1]+gw[grand[x][i-1]][i-1];
    }

    for(int i=0;i<edges[x].size();i++)
    {
        int to=edges[x][i].v;
        if(grand[x][0]==to)continue;

        depth[to]=depth[x]+1;
        grand[to][0]=x;
        gw[to][0]=edges[x][i].w;
        dfs(to);
    }
}

void init()
{
    DEPTH=floor(log(n + 0.0) / log(2.0));
    depth[1]=0;
    memset(grand,0,sizeof(grand));
    memset(gw,0,sizeof(gw));
    dfs(1);
}

int lca(int a,int b)
{
    if(depth[a]>depth[b])swap(a,b);
    int ans=0;
    for(int i=DEPTH;i>=0;i--)
    if(depth[a]<depth[b]&&depth[grand[b][i]]>=depth[a])
    ans+=gw[b][i],b=grand[b][i];

    for(int i=DEPTH;i>=0;i--)
    if(grand[a][i]!=grand[b][i])
    {
        ans+=gw[a][i];
        ans+=gw[b][i];
        a=grand[a][i];
        b=grand[b][i];
    }

    if(a!=b)
    {
        ans+=gw[a][0];
        ans+=gw[b][0];
    }
    return ans;
}


int main()
{
    int a,b;
    scanf("%d",&n);
    for(int i=0;i<n-1;i++)
    {
        scanf("%d %d",&a,&b);
        addedge(a,b,1);
    }

    init();

    int ans=0;
    int m,last=1;
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&a);
        ans+=lca(last,a);
        last=a;
    }
    printf("%d",ans);

    return 0;
}
View Code

 

 

商务旅行

标签:lin   ext   rand   one   and   pad   wrap   eof   分享图片   

原文地址:https://www.cnblogs.com/tian-luo/p/9419938.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!