货车运输(最大生成树+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。
输入输出样例
4 3 1 2 4 2 3 3 3 1 1 3 1 3 1 4 1 3
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)的主要内容,如果未能解决你的问题,请参考以下文章
洛谷T1967 货车运输 Kruskal最大生成树&&倍增LCA
$Noip2013/Luogu1967$ 货车运输 最大生成树+倍增$lca$