山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

NOIP2013 货车运输

3.货车运输

(truck.cpp/c/pas)

【问题描述】

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。

 

【输入输出样例】

truck.in

truck.out

4

3

 

3

 

1

2

4

-1

 

2

3

3

3

 

3

1

1

 

3

 

 

 

1

3

 

 

1

4

 

 

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。

 

 

【思路】

  MST+LCA

  可以知道如果运最大重量的货物,货车所走的一定是最大生成树上的边。

  方法:kruskal求解最大生成树。

  对于每个询问uv,找到两者的最近公共祖先r,那么货车走过的路线就是u->r->v,所以只需要在寻找LCA的时候比较路上的最小边即可。

  方法:暴力。先将uv挪到相同深度上来,然后并行向上寻找公共祖先。

  注意:当uv不属于同一个树中的时候意味着两者不互通,需要提前判断。

【代码】

  1 #include<iostream>
  2 #include<vector>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define FOR(a,b,c) for(int a=(b);a<(c);a++)
  6 using namespace std;
  7 
  8 const int maxn = 10000+10, maxm=50000+10;
  9 int n,m;
 10 int father[maxn];  //并查集 
 11 struct Edge{
 12     int u,v,d;
 13     bool operator <(const Edge& rhs) const{  //最大生成树 
 14       return d>rhs.d;
 15     }
 16 };
 17 struct Edge2{
 18     int v,d,next;
 19 };
 20 inline int find(int u) {
 21     return u==father[u]? u:father[u]=find(father[u]);
 22 }
 23 struct LCA{
 24     int first[maxm];   //链表式存初图 
 25     Edge2 e[maxm]; int en;
 26      
 27     int dist[maxn][maxn];  //[][]
 28     int d[maxn];          //深度数组 
 29     int p[maxn];          //p数组记录父节点 
 30     int root;
 31     
 32     void init() {
 33         en=0; root=n/2;          //root的选取会影响时间 
 34         for(int i=0;i<n;i++) first[i]=-1;
 35         d[0]=0; 
 36     }
 37     void AddEdge(int u,int v,int d){
 38         ++en;
 39         e[en].v=v; e[en].d=d;
 40         e[en].next=first[u];
 41         first[u]=en;
 42     }
 43     void build_tree(int u,int fa) {      //have failed
 44     //根据MST得出的初图(edges)建树->depth[] parent[] dist[][]
 45     //无根树->有根树 
 46            for(int i=first[u];i>0;i=e[i].next)  {  //i=next[i]!!!
 47                int v=e[i].v;
 48                if(v!=fa) {
 49                  d[v]=d[u]+1; dist[u][v]=dist[v][u]=e[i].d;
 50                  build_tree(v,p[v]=u);    //v!=fa 
 51            }
 52            }
 53     }
 54     void Move(int& u,int depth,int &ans){  //u溯回到高度为depth的祖先的位置 
 55         while(d[u]!=depth) { ans=min(ans,dist[u][p[u]]); u=p[u]; }
 56     }
 57     int query(int u,int v) {
 58         if(find(u) != find(v)) return -1; //uv之间不可达
 59         int ans=1<<30;
 60         if(d[u]<d[v]) Move(v,d[u],ans); else if(d[u]>d[v]) Move(u,d[v],ans); 
 61         while(u != v) {
 62             ans=min( ans , min(dist[u][p[u]],dist[v][p[v]]) ); 
 63             u=p[u]; v=p[v];
 64         }
 65         return ans;
 66     }
 67 };
 68 LCA lca;
 69 struct Kruskal{
 70     vector<Edge> edges;
 71     
 72     void init() {
 73         edges.clear();
 74         for(int i=0;i<n;i++) father[i]=i;
 75     }
 76     void AddEdge(int u,int v,int d) {
 77         edges.push_back((Edge){u,v,d});
 78     }
 79     void MST() {
 80         lca.init();
 81         sort(edges.begin(),edges.end());
 82         int cnt=0;
 83         int nc=edges.size();
 84         for(int i=0;i<nc;i++) {
 85             int u=edges[i].u,v=edges[i].v,d=edges[i].d; 
 86             int x=find(u),y=find(v);
 87             if(x!=y) {
 88                 lca.AddEdge(u,v,d);   //利用MST中的边构造lca 
 89                 lca.AddEdge(v,u,d);   //反向边 
 90                 father[x]=y;
 91                 if(++cnt==n-1) return ;  //判断有n-1条边提前结束 
 92             }
 93         }
 94     }
 95 };
 96 
 97 Kruskal krus;
 98 
 99 int main() {
100     ios::sync_with_stdio(false);
101     cin>>n>>m;
102     krus.init();
103     FOR(i,0,m) { //uv 0..
104         int u,v,d;
105         cin>>u>>v>>d; u--; v--; 
106         krus.AddEdge(u,v,d);
107     }
108     krus.MST();
109     lca.build_tree(lca.root,-1);
110     int q; cin>>q;
111     FOR(i,0,q) {
112         int u,v; cin>>u>>v; u--; v--;
113         cout<<lca.query(u,v)<<"\n";
114     }
115     return 0;
116 }

 

posted on 2015-10-07 20:07  hahalidaxin  阅读(206)  评论(0编辑  收藏  举报