您的位置:首页 > 其它

NOIP2013 货车运输

2016-03-30 17:21 399 查看
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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: