做题计蒜客11217 百度地图的实时路况——分治
Posted cly_none
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了做题计蒜客11217 百度地图的实时路况——分治相关的知识,希望对你有一定的参考价值。
又是一道明明简单我却不会的题。
切入点当然是O(n^4)的暴力。显然这其中有大量的重复计算。
一开始的想法是从前往后,从后往前各跑一遍floyd。这样做的关键问题在于如何合并两个floyd的结果。然而我只想出了O(n^3)的合并。故这种做法除了只有暴力1/6的常数(手算得到)之外,就并没有什么卵用了。放弃这个想法。
换言之,我们的做法是需要避免多次添加同一节点。这需要我们对删去一个点的方案进行分类。
然后我就看了题解。
因为我们的结果是单个点被删去,所以考虑从从多个点被删去的状态转移过来。
记dis(l,r)的l到r中的节点尚未被添加时任意两点最短路的集合。我们就可以转移到dis(l,(l+r)/2)和dis((l+r)/2+1,r)了,并且当前状态只会被一个状态转移过来。故每个点只会被添加一次。
时间复杂度O(n^3)。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=305,INF=1e8; 4 int dis[10][N][N],n; 5 long long ans; 6 void floyd(int l,int r,int now) 7 { 8 for(int k=l;k<=r;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) 9 dis[now][i][j]=min(dis[now][i][k]+dis[now][k][j],dis[now][i][j]); 10 } 11 void solve(int l,int r,int now) 12 { 13 if(l==r) 14 { 15 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i!=l&&j!=l) 16 ans+=(dis[now][i][j]==INF?-1:dis[now][i][j]); 17 return; 18 } 19 int mid=(l+r)>>1; 20 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) 21 dis[now+1][i][j]=dis[now][i][j]; 22 floyd(l,mid,now+1); 23 solve(mid+1,r,now+1); 24 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) 25 dis[now+1][i][j]=dis[now][i][j]; 26 floyd(mid+1,r,now+1); 27 solve(l,mid,now+1); 28 } 29 int main() 30 { 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) 33 { 34 scanf("%d",&dis[0][i][j]); 35 dis[0][i][j]=(dis[0][i][j]==-1?INF:dis[0][i][j]); 36 } 37 solve(1,n,0); 38 printf("%lld\n",ans); 39 return 0; 40 }
小结:这大概是我对floyd不够深入了解吧。
以上是关于做题计蒜客11217 百度地图的实时路况——分治的主要内容,如果未能解决你的问题,请参考以下文章