zoukankan      html  css  js  c++  java
  • CF1051F The Shortest Statement

     

    题意:给你一个无向图,有n个点m条边,有t个询问,求询问的两个点的最短距离.

    思路分析:这道题乍一看十分像一道板子题,但是如果你真的把他当板子题来写你就T得爽歪歪了(滑稽~)。

    题目中有一个十分关键的信息,m和n的差不超过20,基于这个信息,我们可以把图分为一棵树和最多20条边,那么我们对待一个询问x,y;可以考虑到有两种情况,一种是最短路的所有路径都在树上,那么我们跑一个LCA即可,那么如果最短路一部分在其他的边上呢?我们只能跑一遍dijkstra(关于SPFA?它死了)来求解,极限情况下我们最多只跑了40遍dijkstra(20条边40个点),相比之下已经快许多了,由于不在树上的路径一定会过路径两边的点,我们只需对每一个相应点跑dijkstra,对于询问比较每个点的情况,和LCA比较求出最小值即可。

    思路说完了,来说一下我调代码时跳的坑。

    1.带longlong的题min函数要自己写,不然会错

    2.lca的depth是深度,不是距离.

    3.求最小生成树并查集一定要初始化,不然优化就没意义了

    4.longlong值以int输出会发生奇妙的错误

    5.建的两张图的变量不要弄混了

    希望可以帮到调代码遇到困难的各位,调代码调不出来太痛苦了。。。

    上代码:

      1 #include<queue>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 typedef long long ll;
      6 using namespace std;
      7 const int N=2e5+10;
      8 ll Min(ll x,ll y){
      9     return x<y?x:y;
     10 }
     11 struct Node{
     12     ll next,to;
     13     ll dis;
     14 }edge[N],tree[N];
     15 ll n,m,v[N];
     16 ll Head_edge[N],Head_tree[N],tot_edge,tot_tree;
     17 void Add_edge(ll x,ll y,ll z){  //生成原图 
     18     edge[++tot_edge].dis=z;
     19     edge[tot_edge].to=y;
     20     edge[tot_edge].next=Head_edge[x];
     21     Head_edge[x]=tot_edge;
     22 }
     23 void Add_tree(ll x,ll y,ll z){  //最小生成树,用于求LCA 
     24     tree[++tot_tree].dis=z;
     25     tree[tot_tree].to=y;
     26     tree[tot_tree].next=Head_tree[x];
     27     Head_tree[x]=tot_tree;
     28 }
     29 ll pa[N],dep[N];
     30 ll find(ll x){ //并查集求最小生成树 
     31     return pa[x]==x?x:(pa[x]=find(pa[x]));
     32 }
     33 void merge(ll x,ll y){
     34     pa[find(x)]=find(y);
     35 }
     36 void Init(ll n){
     37     for(ll i=1;i<=n;++i)
     38         pa[i]=i;
     39 }
     40 struct Edge{ //dijkstra部分 
     41     ll dis;
     42     ll num;
     43     Edge(ll a,ll b){
     44         dis=a;num=b;
     45     }
     46     bool operator < (const Edge &a)const{
     47         return a.dis<dis;
     48     }
     49 };
     50 ll dis[101][N];
     51 ll vis_dij[N],id[N];
     52 priority_queue<Edge>q;
     53 void dijkstra(ll x){
     54     memset(dis[id[x]],0x7f,sizeof(dis[id[x]]));
     55     memset(vis_dij,0,sizeof(vis_dij));
     56     dis[id[x]][x]=0;q.push(Edge(0,x));
     57     while(!q.empty()){
     58         Edge u=q.top();q.pop();
     59         if(vis_dij[u.num]) continue;
     60         vis_dij[u.num]=1;
     61         for(ll i=Head_edge[u.num];i;i=edge[i].next){
     62             ll v=edge[i].to;
     63             if(dis[id[x]][v]>dis[id[x]][u.num]+edge[i].dis){
     64                 dis[id[x]][v]=dis[id[x]][u.num]+edge[i].dis;
     65                 q.push(Edge(dis[id[x]][v],v));
     66             }
     67         }
     68     }
     69 }
     70 ll fa[N],p[N][21];
     71 ll depth[N];
     72 void dfs(ll x,ll pat){  //在生成树上求LCA 
     73     p[x][0]=fa[x];
     74     depth[x]=depth[fa[x]]+1;
     75     for(ll j=0;p[x][j]!=0;++j)
     76         p[x][j+1]=p[p[x][j]][j];
     77     for(ll i=Head_tree[x];i;i=tree[i].next){
     78         ll v=tree[i].to;
     79         if(v==pat) continue;
     80         fa[v]=x;
     81         dep[v]=dep[x]+tree[i].dis;
     82         dfs(v,x);
     83     }
     84 }
     85 ll lca(ll u,ll v){
     86     if(depth[u]<depth[v]) swap(u,v);
     87     ll d=depth[u]-depth[v];
     88     for(ll j=0;d;d>>=1,j++){
     89         if(d&1) u=p[u][j];
     90     }
     91     if(u==v) return u;
     92     for(ll j=20;j>=0;--j){
     93         if(p[u][j]!=p[v][j]){
     94             u=p[u][j];v=p[v][j];
     95         }
     96     }
     97     return fa[u];
     98 }
     99 struct tre{ //用于sort 
    100     ll dis;
    101     ll from,to;
    102     bool operator < (const tre &a)const{
    103         return a.dis<dis;
    104     }
    105 }tr[N];
    106 ll e[N],book[N];
    107 int main(){
    108     scanf("%lld%lld",&n,&m);
    109     Init(n*2);
    110     for(ll i=1;i<=m;++i){
    111         ll x,y;
    112         ll z;
    113         scanf("%lld%lld%lld",&x,&y,&z);
    114         Add_edge(x,y,z);Add_edge(y,x,z); //建原图 
    115         tr[i].from=x;tr[i].to=y;tr[i].dis=z;
    116     }
    117     sort(tr+1,tr+1+m);
    118     for(ll i=1;i<=m;++i){
    119         tre u=tr[i];
    120         ll from=u.from,to=u.to;
    121         ll dist=u.dis;
    122         if(find(from)!=find(to)){
    123             Add_tree(from,to,dist);//建树 
    124             Add_tree(to,from,dist);
    125             merge(from,to);
    126         }
    127         else{
    128             e[from]=e[to]=1; //标记树之外的边 
    129             if(!id[from]){  //数组开不下需要离散化 
    130                 id[from]=++book[0];
    131                 book[book[0]]=from;
    132             }
    133             if(!id[to]){
    134                 id[to]=++book[0];
    135                 book[book[0]]=to;    
    136             } 
    137         }
    138     }
    139     dfs(1,0);
    140     ll t;
    141     for(ll i=1;i<=book[0];++i)
    142         dijkstra(book[i]);  //对树之外的边的每个点求最短路 
    143     scanf("%lld",&t);
    144     for(ll i=1;i<=t;++i){
    145         ll x,y;
    146         scanf("%lld%lld",&x,&y);
    147         ll Lca=lca(x,y);
    148         ll ans=dep[x]+dep[y]-2*dep[Lca];//比较答案 
    149         for(ll i=1;i<=book[0];++i)
    150             ans=Min(ans,dis[i][x]+dis[i][y]);
    151         printf("%lld
    ",ans);
    152     }
    153     return 0;
    154 }
    View Code
  • 相关阅读:
    bottombordertransition – 从中​​间扩展
    P3605 [USACO17JAN]Promotion Counting P
    CF817F MEX Queries
    2021.11.16模拟总结
    动态开点线段树学习笔记
    2021 NOIP 游记
    EntiyFramework :Update model from database引起的两个问题
    .NET Attribute(特性)的作用与用法——几句话解决Attribute使用的困惑
    前端CSS
    前端知识之HTML内容
  • 原文地址:https://www.cnblogs.com/li-jia-hao/p/12861151.html
Copyright © 2011-2022 走看看