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
原文地址:https://www.cnblogs.com/li-jia-hao/p/12861151.html