货车运输(最大生成树+LCA)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了货车运输(最大生成树+LCA)相关的知识,希望对你有一定的参考价值。

题目描述

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入输出格式

输入格式:

 

输入文件名为 truck.in。

输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道

路。 接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意: x 不等于 y,两座城市之间可能有多条道路 。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。

 

输出格式:

 

输出文件名为 truck.out。

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货

车不能到达目的地,输出-1。

 

输入输出样例

输入样例#1:
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
输出样例#1:
3
-1
3

说明

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q< 1,000;

对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q< 1,000;

对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000。

 

 

 

题中要求的是图中任意两点间的路径的最小值最大是多少

 

货车要尽可能的运多的货物,就需要尽可能走权值大的路

所以路径一定在图中的最大生成树上

 

得到最大生成树后,很容易发现两点间的路径一定经过它们的最近公共祖先,

则可以利用倍增的思想,设p[i][j]表示i节点第2^j个祖先,minx[i][j]表示从i到2^j个祖先的路径最小值

 

转移方程:p[i][j]=p[p[i][j-1]][j-1]

     minx[i][j]=min(minx[i][j-1],minx[p[i][j-1][j-1])

 

利用两个数组去求lca和最小路径即可

 

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#define MAXN 10050
#define MAXE 50050
#define INF 2147483647
using namespace std;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
int father[MAXN];
int finds(int x)
{
    if(father[x]==x) return x;
    return father[x]=finds(father[x]);
}
struct Line
{
    int u,v,w;
    friend bool operator<(Line a,Line b)
    {
        return a.w>b.w;
    }
} l[MAXE];
struct Edge
{
    int u,v,w;
    int next;
} e[MAXE];
int head[MAXN],cnt=0;
void add(int u,int v,int w)
{
    cnt++;
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
int n,m,q,deep[MAXN],p[MAXN][20],minx[MAXN][20],deps;
void kruskal()
{
    for(int i=1; i<=n; i++)father[i]=i;
    sort(l+1,l+m+1);
    for(int i=1; i<=m; i++)
    {
        int u=finds(l[i].u);
        int v=finds(l[i].v);
        if(u!=v)
        {
            father[v]=u;
            add(l[i].u,l[i].v,l[i].w);
            add(l[i].v,l[i].u,l[i].w);
        }
    }
}
void dfs(int u)
{
    for(int i=head[u]; i!=0; i=e[i].next)
        if(!deep[e[i].v])
        {
            deep[e[i].v]=deep[u]+1;
            p[e[i].v][0]=u;
            minx[e[i].v][0]=e[i].w;
            dfs(e[i].v);
        }
}
inline int lca(int x, int y)
{
    int ans=INF;
    if(deep[x]>deep[y]) swap(x, y);
    for(int i=15; i>=0; i--)
        if(deep[p[y][i]]>=deep[x])
        {
            ans=min(ans,minx[y][i]);
            y=p[y][i];
        }
    if(x==y) return ans;
    for(int i=15; i>=0; i--)
        if(p[x][i]!=p[y][i])
        {
            ans = min(ans, min(minx[x][i], minx[y][i]));
            x=p[x][i];
            y=p[y][i];
        }
    return min(ans, min(minx[x][0], minx[y][0]));
}
int main()
{
    n=read(),m=read();
    for(int i=1; i<=m; i++)
        l[i].u=read(),l[i].v=read(),l[i].w=read();
    kruskal();
    deep[1]=1;
    dfs(1);
    for(int j=1; j<=15; j++)
        for(int i=1; i<=n; i++)
        {
            p[i][j]=p[p[i][j-1]][j-1];
            minx[i][j]=min(minx[i][j-1],minx[p[i][j-1]][j-1]);
        }
    q=read();
    for(int i=1; i<=q; i++)
    {
        int u=read(),v=read();
        if(finds(u)!=finds(v))
        {
            printf("-1\n");
            continue;
        }
        printf("%d\n",lca(u,v));
    }
}

 

以上是关于货车运输(最大生成树+LCA)的主要内容,如果未能解决你的问题,请参考以下文章

货车运输(最大生成树+LCA)

洛谷T1967 货车运输 Kruskal最大生成树&&倍增LCA

P1967 货车运输最大生成树+倍增LCA!!!

$Noip2013/Luogu1967$ 货车运输 最大生成树+倍增$lca$

luogu1967noip2013 货车运输 [生成树kruskal LCA ]

NOIP2013 货车运输 [LCA+最大生成树]