• HDU:2586-How far away


    How far away

    Time limit1000 ms
    Memory limit32768 kB

    Problem Description

    There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.

    Input

    First line is a single integer T(T<=10), indicating the number of test cases.
    For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0 < k <= 40000).The houses are labeled from 1 to n.
    Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.

    Output

    For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.

    Sample Input

    2
    3 2
    1 2 10
    3 1 15
    1 2
    2 3

    2 2
    1 2 100
    1 2
    2 1

    Sample Output

    10
    25
    100
    100


    解题心得:

    1. 题意就是给你一个双向图,每两点之间只有一条路径(其实就是一颗树),任意问你两点,要求输出两点间的最小距离。两种做法:
      • 第一种就是直接跑暴力的dfs,复杂度也就是n*m最大8e6,很简单就跑过了。
      • 第二种就是用LCA,两点之间最短的距离就是两点经过最近公共祖先形成的一条路。具体做法可以先预处理一下每个点到根节点的距离,存在数组dis里面,假如询问a,b之间的最小距离,就可以先得出最近公共祖先c然后答案就是dis[a] + dis[b] - 2*dis[c]。
    2. 然后就是双向边怎么建成一棵树的问题,可以用邻接表存图,存双向边,在使用的时候任意选一个点为根节点,使用过的点就标记上,这样就可以形成一棵树,因为每两点之间只选择一个方向的边。

    dfs跑暴力:

    #include<stdio.h>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int maxn = 4e4+100;
    bool vis[maxn],flag;
    int n,m,ans,a,b;
    vector <pair<int,int> > ve[maxn];
    
    void init()
    {
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n+1;i++)
            ve[i].clear();
        for(int i=1;i<n;i++)
        {
            int a,b,len;
            scanf("%d%d%d",&a,&b,&len);
            //邻接表存图
            ve[a].push_back(make_pair(b,len));
            ve[b].push_back(make_pair(a,len));
        }
    }
    
    void dfs(int pos,int sum_len)
    {
        if(vis[pos] || flag)
            return ;
        vis[pos] = true;
        if(pos == b)
        {
            printf("%d
    ",sum_len);
            flag = true;
            return;
        }
        for(int i=0;i<ve[pos].size();i++)
        {
            pair<int,int> p;
            p = ve[pos][i];
            dfs(p.first,sum_len + p.second);
        }
    }
    
    void solve()
    {
        while(m--)
        {
            flag = false;
            memset(vis,0,sizeof(vis));
            scanf("%d%d",&a,&b);
            dfs(a,0);
        }
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            init();
            solve();
        }
    }

    LCA(tarjan写法)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 4e4+100;
    vector <pair<int,int> > ve[maxn];
    int vis[maxn],n,father[maxn],sum[maxn],m,a,b;
    bool flag;
    
    void init()
    {
        memset(father,0,sizeof(father));
        memset(vis,0,sizeof(vis));
        memset(sum,0,sizeof(sum));
        for(int i=0; i<=n; i++)
            ve[i].clear();
        for(int i=1; i<n; i++)
        {
            int a,b,len;
            scanf("%d%d%d",&a,&b,&len);
            ve[a].push_back(make_pair(b,len));
            ve[b].push_back(make_pair(a,len));
        }
    }
    
    void dfs(int pos,int len)
    {
        vis[pos] = true;
        sum[pos] = len;
        for(int i=0; i<ve[pos].size(); i++)
        {
            int v = ve[pos][i].first;
            if(!vis[v])
                dfs(v,len+ve[pos][i].second);
        }
        return ;
    }
    
    int find(int x)
    {
        if(x == father[x])
            return x;
        return father[x] = find(father[x]);
    }
    
    void tarjan(int pos)//跑tarjan
    {
        vis[pos] = true;
        father[pos] = pos;
        if(flag)
            return;
        for(int i=0; i<ve[pos].size(); i++)
        {
            int v = ve[pos][i].first;
            if(!vis[v])
            {
                tarjan(v);
                father[v] = pos;
            }
            if(flag)
                return ;
        }
        if(pos == a || pos == b)
        {
            if(pos != a)
                swap(a,b);
            if(father[b])
            {
                int ans = find(father[b]);
                printf("%d
    ",abs(sum[a]+sum[b]-sum[ans]*2));
                flag = true;
            }
        }
    }
    
    void query()
    {
        while(m--)
        {
            flag = false;
            memset(father,0,sizeof(father));
            memset(vis,0,sizeof(vis));
            scanf("%d%d",&a,&b);
            tarjan(1);
        }
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            init();
            dfs(1,0);//先dfs预处理
            query();
        }
    }
  • 相关阅读:
    python统计代码总行数(代码行、空行、注释行)
    selenium常用的API(二)浏览器窗口设置
    selenium常用的API(一)截屏
    python中的yield
    python中的lambda、map、reduce、filter
    python中的exec和eval
    MySQL中的information_schema
    单元测试框架Unittest
    MySQL批量修改相同后缀表名
    【python自动化第十一篇】
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107209.html
Copyright © 2020-2023  润新知