题解报告——货车运输

题目描述

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。


【思路分析】 

由于我们这道题只需要知道最大载货量,对于路径的长度没有要求的,所以我们只需要在最大的边上跑就好。那么怎么找最大边,那么就将最小生成树改一下,将边排序时从小到大改为从大到小,变成最大生成树,就可以在保证当前图中的每个点联通并且边权最大,就可以省去跑一些权值小的边的时间,然后就在这个图上跑LCA,跑LCA的时候顺便统计到公共祖先的路径上的最小边,然后输出就好。

值得注意的是这个地方的点可能不是一个连通图,可能有多个,所以要在多个树上跑LCA,不过就是一个for循环的事

最好先看看倍增LCA,只要会倍增LCA,那么这道题写出代码还是很快的

具体看代码!

【代码实现】 

  1 #include<cstdio>
  2 #include<vector>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 using namespace std;
  7 const int MAXN=1e6+7;
  8 struct sd{
  9     int ww,id;//记录到哪个节点,路径权值是多少
 10 }jump[10005][21],fa[10005];//用于跑LCA的结构体
 11 struct sd1{
 12     int next,to,w;
 13 }edge[50005];//用于最大生成树的结构体
 14 int ff[10005];//并查集
 15 int deep[10005];
 16 bool vis[10005];
 17 vector<sd> son[10005];//记录跑LCA的树
 18 vector<sd> link[10005];//记录之前的无向图
 19 int n,m,q;
 20 void find(int v)//倍增LCA
 21 {
 22     for(int i=1;i<=20;i++)
 23     {
 24         int temp=jump[v][i-1].id;
 25         jump[v][i].id=jump[temp][i-1].id;
 26         jump[v][i].ww=min(jump[v][i-1].ww,jump[temp][i-1].ww);
 27     }
 28 }
 29 void pre(int v)//LCA的预处理
 30 {
 31     deep[v]=deep[fa[v].id]+1;
 32     jump[v][0].id=fa[v].id;
 33     jump[v][0].ww=fa[v].ww;
 34     find(v);
 35     int ss=son[v].size();
 36     if(ss==0) 
 37     return;
 38     for(int i=0;i<ss;i++)
 39         pre(son[v][i].id);
 40 }
 41 int lca(int a,int b)//跑LCA
 42 {
 43     if(deep[b]>deep[a]) {int t=a;a=b;b=t;}
 44     int len=deep[a]-deep[b];
 45     int ans=MAXN;
 46     if(len!=0)
 47     {
 48         for(int i=20;i>=0;i--)
 49         {
 50             if(deep[jump[a][i].id]>=deep[b])
 51             {
 52                 ans=min(ans,jump[a][i].ww);
 53                 a=jump[a][i].id;
 54             }
 55         }
 56     }
 57     if(a==b) return ans;//如果两个节点属于祖先与后代关系,就不用继续了
 58     for(int i=20;i>=0;i--)
 59     {
 60         if(jump[a][i].id!=jump[b][i].id)
 61         {
 62             ans=min(jump[a][i].ww,ans);
 63             ans=min(jump[b][i].ww,ans);
 64             a=jump[a][i].id,b=jump[b][i].id;
 65         }
 66     }
 67     ans=min(ans,fa[a].ww);
 68     ans=min(ans,fa[b].ww);
 69     return ans;
 70 }
 71 bool cmp(sd1 a,sd1 b)
 72 {
 73     return a.w>b.w;
 74 }
 75 int father(int v)
 76 {
 77     if(ff[v]!=v) return ff[v]=father(ff[v]);
 78     return v;
 79 }
 80 void dfs(int v)//预处理建立跑LCA的图
 81 {
 82     vis[v]=true;
 83     int ss=link[v].size();
 84     for(int i=0;i<ss;i++)
 85     {
 86         if(vis[link[v][i].id]==false)
 87         {
 88             son[v].push_back(link[v][i]);
 89             fa[link[v][i].id].id=v;
 90             fa[link[v][i].id].ww=link[v][i].ww;
 91             dfs(link[v][i].id);
 92         }
 93     }
 94 }
 95 void kls()//克鲁斯卡尔预处理
 96 {
 97     sort(edge+1,edge+1+m,cmp);
 98     for(int i=1;i<=n;i++) ff[i]=i;
 99     for(int i=1;i<=m;i++)
100     {
101         int f1=father(edge[i].next);
102         int f2=father(edge[i].to);
103         if(f1!=f2) 
104         {
105             ff[f1]=f2;
106             sd gg1,gg2;
107             gg1.id=edge[i].to,gg1.ww=edge[i].w;
108             gg2.id=edge[i].next,gg2.ww=edge[i].w;
109             link[edge[i].next].push_back(gg1);
110             link[edge[i].to].push_back(gg2);
111         }
112     }
113 }
114 int main()
115 {
116     memset(vis,false,sizeof(vis));
117     scanf("%d%d",&n,&m);
118     for(int i=1;i<=m;i++)
119     {
120         int x,y,w1;
121         scanf("%d%d%d",&x,&y,&w1);
122         edge[i].next=x,edge[i].to=y,edge[i].w=w1;
123     }
124     kls();
125     for(int i=1;i<=n;i++)//循环建立树,防止不止一个联通图
126     {
127         if(vis[i]) continue;
128         deep[i]=1; 
129         dfs(i);
130         pre(i);
131     }
132     scanf("%d",&q);
133     for(int i=1;i<=q;i++)
134     {
135         int a,b;
136         scanf("%d%d",&a,&b);
137         if(father(a)!=father(b))//如果不在一个联通图上,那么肯定不能相互到达
138         {
139             printf("-1\n");
140             continue;
141         }
142         printf("%d\n",lca(a,b));
143     }
144     return 0;
145 }

 

posted @ 2018-03-28 21:25  genius777  阅读(259)  评论(0编辑  收藏  举报