版权声明:本文为博主原创文章,未经博主允许不得转载。
传送门:货车运输
题目描述
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。
算法:倍增,最小生成树
Solution:很明显,这道题所想要使用的路径一定是权值尽量大的。因为路径的权值越大,载重量越多。因此我们所有的货车都会在路径权值尽量大的路径上跑,可以用最小生成树反过来,也就是构造说所谓的“最大”生成树。构造树之后,我们可以保证货车按题目要求所经过的所有路径必定在这棵树上,因为这是一个路径尽量大权值的集合。然后就可以用LCA的模板,因为载重量的大小由路径上权值最小的路径权值决定,所以我们可以顺便在过程中记录一个数组下标意义与Father[i][j]相同的Dis[i][j]。表示这i到第2^j个父亲这一段路上路径的最小权值。然后就可以出解了。
Hint:
kruskal中并查集的数组Father大小一定要开到最大边数,初始化也要初始到边数m。
求LCA的时候返回的是路径上的最小权值每次用Ans进行比较。
构造成树的边数只需开到2倍点数n。
递推LCA如果像如下代码一样放在DFS外面进行递推一定要先循环j再循环i。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 5 const int MAXN = 10001; 6 const int MAXM = 50001; 7 const int MAX = 15; 8 9 struct DATA{ 10 int u,v,Dis; 11 bool operator < (DATA Tmp) const {return Tmp.Dis<Dis;} 12 }Data[MAXM]; 13 int Father[MAXM]; 14 int Find(int t){ 15 return t==Father[t]?t:Father[t]=Find(Father[t]); 16 } 17 18 struct EDGE{ 19 int Next,To,Dis; 20 }Edge[MAXN<<1|1]; 21 int Head[MAXN<<1|1],Size; 22 void Ins(int From,int To,int Dis){ 23 Edge[++Size].Next=Head[From]; 24 Head[From]=Size; 25 Edge[Size].To=To; 26 Edge[Size].Dis=Dis; 27 } 28 29 int n,m,q; 30 int Indgr[MAXN]; 31 32 int Deep[MAXN],f[MAXN][MAX+1],Dis[MAXN][MAX+1];bool Vis[MAXN]; 33 void Dfs(int u){ 34 for(int i=Head[u];i;i=Edge[i].Next){ 35 int v=Edge[i].To; 36 if(Vis[v]) continue;Vis[v]=1; 37 Dis[v][0]=Edge[i].Dis; 38 Deep[v]=Deep[u]+1;f[v][0]=u; 39 Dfs(v); 40 } 41 } 42 43 void Make_Tree(){ 44 for(int i=1;i<=m;i++) Father[i]=i; 45 sort(1+Data,1+m+Data); 46 47 for(int i=1;i<=m;i++){ 48 int u=Find(Data[i].u),v=Find(Data[i].v); 49 if(u!=v){ 50 Father[u]=v;Indgr[Data[i].u]++;Indgr[Data[i].v]++; 51 Ins(Data[i].u,Data[i].v,Data[i].Dis); 52 Ins(Data[i].v,Data[i].u,Data[i].Dis); 53 } 54 } 55 56 for(int i=1;i<=n;i++) 57 if(Indgr[i]<=2&&!Vis[i]){ 58 Vis[i]=1; 59 Dfs(i); 60 } 61 for(int j=1;j<=MAX;j++)for(int i=1;i<=n;i++){ 62 f[i][j]=f[f[i][j-1]][j-1]; 63 Dis[i][j]=min(Dis[i][j-1],Dis[f[i][j-1]][j-1]); 64 } 65 } 66 67 int LCA(int u,int v){ 68 if(Deep[u]<Deep[v]) swap(u,v); 69 int D_Value=Deep[u]-Deep[v],Ans=Data[1].Dis; 70 for(int i=0;i<=MAX;i++) 71 if(D_Value&(1<<i)) 72 {Ans=min(Ans,Dis[u][i]);u=f[u][i];} 73 if(u==v) return Ans; 74 for(int i=MAX;i>=0;i--) 75 if(f[u][i]!=f[v][i]){ 76 Ans=min(min(Dis[u][i],Dis[v][i]),Ans); 77 u=f[u][i];v=f[v][i]; 78 } 79 return min(Ans,min(Dis[u][0],Dis[v][0])); 80 } 81 82 template <typename Type> inline void Read(Type &in){ 83 Type f=1;char ch=getchar();in=0; 84 for(;ch>‘9‘||ch<‘0‘;ch=getchar())if(ch==‘-‘)f=-1; 85 for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar())in=in*10+ch-‘0‘;in*=f; 86 } 87 88 int main(){ 89 Read(n);Read(m); 90 for(int i=1;i<=m;i++){ 91 Read(Data[i].u);Read(Data[i].v);Read(Data[i].Dis); 92 } 93 Make_Tree(); 94 95 Read(q); 96 for(int i=1,u,v;i<=q;i++){ 97 Read(u);Read(v); 98 printf("%d\n",Find(u)!=Find(v)?-1:LCA(u,v)); 99 } 100 101 return 0; 102 }