• NOIP201307货车运输


    试题描述:A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    输入描述:

    第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
    接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
    接下来一行有一个整数 q,表示有 q 辆货车需要运货。
    接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

    输出描述:

    输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

    样例输入:

    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3

    样例输出:

    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。

    题解:这道题其实就是让我们找一条路使得这条路上的最小值最大,由此我们不难想到对任意的从u到v的一条我们所需的路径,一定是在这个图的最大生成树上,所以我们可以先构造最大生成树。

    对于任意一组(u,v)(从u到v)用并查集可以判断如果u、v的祖先不同,那就说明u、v之间没有路

    如果有路,我们用lca(最近公共祖先)来进行判断。假设u、v的lca是t,那么最终我们需要的答案就是min(u到t的最短路限重,v到t的最短路限重),这样我们这个题就直接ac了

    AC代码如下:

      1 #include<iostream>
      2 #include<cctype>
      3 #include<algorithm>
      4 #include<memory.h>
      5 using namespace std;
      6 const int MAXN=100000+10;
      7 int n,m;
      8 //-------------------------
      9 void read(int &x){
     10     x=0;int f=1;char ch=getchar();
     11     for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
     12     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
     13     x*=f;
     14 }//读入函数 
     15 //-------------------------
     16 struct edge{
     17     int u,v,w;
     18     edge(){u=0;v=0;w=0;}
     19 }to[50010];
     20 bool operator < (edge a,edge b){return a.w>b.w;}
     21 //-------------------------
     22 int fa[10010];
     23 int find(int x){
     24     if(x==fa[x])return x;
     25     return fa[x]=find(fa[x]);
     26 }//并查集 
     27 //-------------------------
     28 int v[MAXN],w[MAXN],first[MAXN],next[MAXN],e;
     29 void AddEdge(int a,int b,int c){
     30     v[++e]=b;
     31     w[e]=c;
     32     next[e]=first[a];
     33     first[a]=e;
     34 }//邻接表 
     35 void MST(){//最大生成树 
     36     int cnt=0;
     37     sort(to+1,to+m+1);
     38     for(int i=1;i<=n;i++)fa[i]=i;
     39     for(int i=1;i<=m;i++){
     40         int p=find(fa[to[i].v]),q=find(fa[to[i].u]);
     41         if(p!=q){
     42             fa[p]=q;
     43             AddEdge(to[i].v,to[i].u,to[i].w);
     44             AddEdge(to[i].u,to[i].v,to[i].w);
     45             cnt++;
     46         }
     47         if(cnt==n-1)break;
     48     }
     49 }
     50 //------------------------
     51 int parent[17][10010];
     52 int depth[10010];
     53 int dist[17][MAXN]; 
     54 bool vis[10010];
     55 void dfs(int x,int p,int d){
     56     vis[x]=1;
     57     parent[0][x]=p;
     58     depth[x]=d;
     59     for(int i=first[x];i;i=next[i]){
     60         if(vis[v[i]])continue;
     61         dist[0][v[i]]=w[i];
     62         dfs(v[i],x,d+1);
     63     }
     64 }
     65 
     66 void init(){//初始化 
     67     for(int i=1;i<=n;i++)if(!vis[i])dfs(i,-1,0);
     68     for(int k=0;k+1<=16;k++){
     69         for(int i=1;i<=n;i++){
     70             if(parent[k][i]<0)parent[k+1][i]=-1;
     71             else parent[k+1][i]=parent[k][parent[k][i]];
     72             dist[k+1][i]=min(dist[k][parent[k][i]],dist[k][i]);
     73         }
     74     }
     75 }
     76 
     77 int lca(int x,int y){//最近公共祖先 
     78     if(depth[y]>depth[x])swap(x,y);
     79     for(int k=0;k<=16;k++)
     80         if((depth[x]-depth[y])>>k&1)
     81             x=parent[k][x];
     82     if(x==y)return x;
     83     for(int k=16;k>=0;k--){
     84         if(parent[k][x]!=parent[k][y]){
     85             x=parent[k][x];
     86             y=parent[k][y];
     87         }
     88     }
     89     return parent[0][x];
     90 }
     91 //------------------------------
     92 int work(int x,int y){
     93     int u=lca(x,y);
     94     int t1=depth[x]-depth[u];
     95     int t2=depth[y]-depth[u];
     96     int minn1=-1u>>1,minn2=-1u>>1;
     97     for(int i=0;i<=16;i++){
     98         if((t1&(1<<i))){
     99             minn1=min(minn1,dist[i][x]);
    100             x=parent[i][x];
    101         }
    102         if(t2&(1<<i)){
    103             minn2=min(minn2,dist[i][y]);
    104             y=parent[i][y];
    105         }
    106     }
    107     return min(minn1,minn2);
    108 }
    109 //-------------------------------
    110 int main(){
    111     memset(dist,127/3,sizeof(dist));
    112     read(n);read(m);
    113     for(int i=1;i<=m;i++){
    114         read(to[i].u);
    115         read(to[i].v);
    116         read(to[i].w);
    117     }
    118     MST();
    119     init();
    120     int q;
    121     read(q);
    122     while(q--){
    123         int x,y;
    124         read(x);read(y);
    125         if(find(x)!=find(y)){
    126             printf("-1
    ");
    127             continue;
    128         }
    129         printf("%d
    ",work(x,y));
    130     }
    131 }
    View Code
  • 相关阅读:
    Redis安装
    mysql 存储过程与存储函数
    mysql 常用函数
    cpu-z笔记本加条子
    centos上网络服务起不来network.service failed
    centos/redhat命令行上传下载文件
    docker删除已经停止的容器
    centos/redhat/ubuntu不同之处
    部署lamp动态网站(图解)
    写交互式脚本时,遇到到报错:not a regular file
  • 原文地址:https://www.cnblogs.com/543Studio/p/5192104.html
Copyright © 2020-2023  润新知