• 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
    ",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
    ",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('
    ');
    106     }
    107     return 0;
    108 }
    非暴力100分 

      

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

  • 相关阅读:
    经济--1...19
    经济
    金融--
    经济--番外篇
    经济--基金问答
    经济--如何买基金?
    PHP面向对象常见的关键字和魔术方法
    php对象中类的继承性访问类型控制
    详解PHP的__set()、__get()、__isset()、unset()四个方法
    子类重载父类的方法“parent:方法名”
  • 原文地址:https://www.cnblogs.com/RisingGods/p/8470414.html
Copyright © 2020-2023  润新知