NOIP2013 货车运输

题目描述

  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。

  暴力30分:

    读入q之后直接将每一个读入的x点当做源点,跑spfa,用x更新每一个点,最后输出源点到终点y的距离即可。

    这里的spfa中,将最短路改成了求所有路径中,使到达终点的边权值的最小值最大:dis[v]=min(edge[i].val,dis[u]);就是用min(到达该路径起点的最小限重,该路径的限重)来更新下一个点。

 1 #include<cstdio>
 2 #include<queue>
 3 using namespace std;
 4 const int maxn=1e4+5,maxm=5e4+5,inf=2147483647;
 5 int head[maxn],dis[maxn];
 6 bool inq[maxn];
 7 int num,n,m;
 8 queue<int> q;
 9 struct cp{
10     int to,val,next;
11 }edge[maxm<<1];
12 inline void add(int u,int v,int w){
13     edge[++num].to=v;
14     edge[num].val=w;
15     edge[num].next=head[u];
16     head[u]=num;
17 }
18 int min(int a,int b){
19     return a<b?a:b;
20 }
21 int max(int a,int b){
22     return a>b?a:b;
23 }
24 void spfa(int s){
25     for(int i=1;i<=n;i++) dis[i]=-1,inq[i]=0;
26     while(!q.empty()) q.pop();
27     q.push(s);
28     dis[s]=inf;
29     inq[s]=1;
30     while(!q.empty()){
31         int u=q.front();
32         inq[u]=0;
33         q.pop();
34         for(int i=head[u];i;i=edge[i].next){
35             int v=edge[i].to;
36             if(dis[v]<min(edge[i].val,dis[u])){
37                 dis[v]=min(edge[i].val,dis[u]);
38                 if(!inq[v]){
39                     q.push(v);
40                     inq[v]=1;
41                 }
42             }
43         }
44     }
45 }
46 inline int read(){
47     char ch=getchar();
48     int x=0,f=1;
49     while(ch<'0'||ch>'9'){
50         if(ch=='-') f=-1;
51         ch=getchar();
52     }
53     while(ch>='0'&&ch<='9'){
54         x=(x<<1)+(x<<3)+(ch^48);
55         ch=getchar();
56     }
57     return x*f;
58 }
59 int main(){
60     n=read(),m=read();
61     int x,y,z;
62     while(m--){
63         x=read(),y=read(),z=read();
64         add(x,y,z),add(y,x,z);
65     }
66     int q=read();
67     while(q--){
68         x=read(),y=read();
69         spfa(x);
70         eprintf("%d\n",dis[y]);
71     }
72     return 0;
73 }
暴力30分

  暴力60分:

    因为我们是使路径中的最小限重最大,则如果我们建一颗最大生成树,则从x到y的路径一定是最优的(因为既然可以从x到达y,那么肯定是先按照大的边走答案才会最优)。

    其中spfa部分不变,只是建一颗最大生成树将边的数目降到 n 的级别上,这样从每个点开始乱跑也可以混过去60分。

 

 1 #include<cstdio>
 2 #include<queue>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn=1e4+5,maxm=5e4+5,inf=2147483647;
 7 int head[maxn],dis[maxn],f[maxn];
 8 bool inq[maxn];
 9 int num,n,m;
10 queue<int> q;
11 struct cp{
12     int to,val,next;
13 }edge[maxm<<1];
14 struct cpp{
15     int u,v,w;
16 }e[maxm<<1];
17 bool cmp(cpp a,cpp b){
18     return a.w>b.w;
19 }
20 inline void add(int u,int v,int w){
21     edge[++num].to=v;
22     edge[num].val=w;
23     edge[num].next=head[u];
24     head[u]=num;
25 }
26 int min(int a,int b){
27     return a<b?a:b;
28 }
29 int max(int a,int b){
30     return a>b?a:b;
31 }
32 int find(int x){
33     if(f[x]==x) return x;
34     return f[x]=find(f[x]);
35 }
36 void Union(int a,int b){
37     int x=find(a),y=find(b);
38     f[x]=y;
39 }
40 void spfa(int s){
41     for(int i=1;i<=n;i++) dis[i]=-1,inq[i]=0;
42     while(!q.empty()) q.pop();
43     q.push(s);
44     dis[s]=inf;
45     inq[s]=1;
46     while(!q.empty()){
47         int u=q.front();
48         inq[u]=0;
49         q.pop();
50         for(int i=head[u];i;i=edge[i].next){
51             int v=edge[i].to;
52             if(dis[v]<min(edge[i].val,dis[u])){
53                 dis[v]=min(edge[i].val,dis[u]);
54                 if(!inq[v]){
55                     q.push(v);
56                     inq[v]=1;
57                 }
58             }
59         }
60     }
61 }
62 inline int read(){
63     char ch=getchar();
64     int x=0,f=1;
65     while(ch<'0'||ch>'9'){
66         if(ch=='-') f=-1;
67         ch=getchar();
68     }
69     while(ch>='0'&&ch<='9'){
70         x=(x<<1)+(x<<3)+(ch^48);
71         ch=getchar();
72     }
73     return x*f;
74 }
75 int main(){
76     n=read(),m=read();
77     int x,y,z;
78     for(int i=1;i<=n;i++) f[i]=i;
79     for(int i=1;i<=m;i++) e[i].u=read(),e[i].v=read(),e[i].w=read();
80     sort(e+1,e+m+1,cmp);
81     for(int i=1;i<=m;i++){
82         x=e[i].u,y=e[i].v,z=e[i].w;
83         if(find(x)!=find(y)){
84             add(x,y,z),add(y,x,z);
85             Union(x,y);
86         }
87     }
88     int q=read();
89     while(q--){
90         x=read(),y=read();
91         spfa(x);
92         printf("%d\n",dis[y]);
93     }
94     return 0;
95 }
暴力60分

 

  非暴力100分:

    既然我们建了最大生成树了,那为什么不直接用lca来求==

    在这里我用dis数组表示从x到y路径中的最小值,最后输出答案的时候用solve函数判断一下即可。

 

  1 #include<algorithm>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cmath>
  5 #define ll long long
  6 #define dd double
  7 using namespace std;
  8 const int maxn=1e4+5,maxm=5e4+5,inf=0x7ffffff;
  9 int n,m,q,num,m_dep,s;
 10 int f[maxn],head[maxn],edge[maxn];
 11 int dep[maxn]={-1},fa[maxn][20],dis[maxn][20];
 12 bool inq[maxn];
 13 struct cp{
 14     int u,v,w;
 15 }a[maxm];
 16 struct cpp{
 17     int to,nxt,w;
 18 }e[maxn<<1];
 19 inline void add(int u,int v,int w){
 20     e[++num]=(cpp){v,head[u],w};
 21     head[u]=num;
 22     e[++num]=(cpp){u,head[v],w};
 23     head[v]=num;
 24 }
 25 inline int max(int a,int b){return a>b?a:b;}
 26 inline int min(int a,int b){return a<b?a:b;}
 27 inline void swap(int &x,int &y){x^=y^=x^=y;}
 28 bool cmp(cp x,cp y){return x.w>y.w;}
 29 int find(int x){
 30     if(f[x]==x) return x;
 31     return f[x]=find(f[x]);
 32 }
 33 void Union(int a,int b){
 34     int x=find(a),y=find(b);
 35     f[x]=y;
 36 }
 37 void dfs(int x){
 38     inq[x]=1;
 39     for(int i=head[x];i;i=e[i].nxt){
 40         int v=e[i].to;
 41         if(inq[v]) continue;
 42         dep[v]=dep[x]+1;
 43         m_dep=max(m_dep,dep[v]);
 44         fa[v][0]=x;
 45         dis[v][0]=e[i].w;
 46         dfs(v);
 47     }
 48 }
 49 inline void prepare(){
 50     s=log2(m_dep);
 51     for(int i=1;i<=s;i++) for(int j=1;j<=n;j++)
 52         fa[j][i]=fa[fa[j][i-1]][i-1],
 53         dis[j][i]=min(dis[j][i-1],dis[fa[j][i-1]][i-1]);
 54 }
 55 inline int lca(int x,int y){
 56     if(dep[x]<dep[y]) swap(x,y);
 57     if(dep[x]!=dep[y]) for(int i=s;i>=0;i--)
 58         if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
 59     if(x==y) return x;
 60     for(int i=s;i>=0;i--) if(fa[x][i]!=fa[y][i])
 61         x=fa[x][i],y=fa[y][i];
 62     return fa[x][0];
 63 }
 64 inline int solve(int x,int y){
 65     int ans=inf;
 66     for(int i=s;i>=0;i--) if(dep[fa[x][i]]>=dep[y])
 67         ans=min(ans,dis[x][i]),x=fa[x][i];
 68     return ans;
 69 }
 70 inline int read(){
 71     char ch=getchar();
 72     int x=0,f=1;
 73     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 74     while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
 75     return x*f;
 76 }
 77 void write(int x){
 78     if(x<0) x=-x,putchar('-');
 79     if(x>9) write(x/10);
 80     putchar(x%10^48);
 81 }
 82 int main(){
 83     int cnt=0;
 84     n=read(),m=read();
 85     memset(dis,63,sizeof dis);
 86     for(int i=1;i<=n;i++) f[i]=i;
 87     for(int i=1;i<=m;i++) a[i].u=read(),a[i].v=read(),a[i].w=read();
 88     sort(a+1,a+m+1,cmp);
 89     for(int i=1;i<=m;i++){
 90         int x=a[i].u,y=a[i].v;
 91         if(find(x)!=find(y))
 92             Union(x,y),add(x,y,a[i].w),++cnt;
 93         if(cnt==n-1) break;
 94     }
 95     for(int i=1;i<=n;i++) if(!inq[i]) dfs(i);
 96     prepare();
 97     q=read();
 98     while(q--){
 99         int x=read(),y=read();
100         if(find(x)!=find(y)) write(-1);
101         else{
102             int t=lca(x,y);
103             write(min(solve(x,t),solve(y,t)));
104         }
105         putchar('\n');
106     }
107     return 0;
108 }
非暴力100分 

  

  在这里,特别感谢hzwer(黄学长),他的博客写的真的特别好,有很多模板和题目在他的博客里都有,这道题目也是通过黄学长的博客才A掉的,大家如果还有什么看不懂的地方的话,也可以参考一下黄学长的博客 →→→  hzwer(货车运输)

 

posted @ 2018-02-25 19:57  Rising_Date  阅读(258)  评论(0编辑  收藏  举报