算法:分治+floyd_计蒜之道复赛A题 百度地图的实时路况

来源:互联网 发布:贱人软件5.9破解 编辑:程序博客网 时间:2024/05/16 23:48

题目:

百度地图的实时路况功能相当强大,能方便出行的人们避开拥堵路段。一个地区的交通便捷程度就决定了该地区的拥堵情况。假设一个地区有 n 个观测点,编号从 1 到 n。定义 d(u,v,w) 为从 u号点出发,严格不经过 v 号点,最终到达 ww 号点的最短路径长度,如果不存在这样的路径,d(u,v,w) 的值为 -1。

那么这个地区的交通便捷程度 P 为:

P= 1x,y,zn,xy,yz d(x,y,z) 

现在我们知道了该地区的 n 个点,以及若干条有向边,求该地区的交通便捷程度 P。

输入格式

第一行输入一个正整数 n(4n300) ,表示该地区的点数。

接下来输入 n 行,每行输入 n 个整数。第 i 行第 j 个数G i,j (1G i,j 10000;G i,i =0) 表示从 i 号点到 j 号的有向路径长度。如果这个数为 -1,则表示不存在从 i 号点出发到 j号点的路径。

输出格式

输出一个整数,表示这个地区的交通便捷程度。

样例输入

4
0 1 -1 -1
-1 0 1 -1
-1 -1 0 1
1 -1 -1 0
样例输出

4

        一开始使用枚举来Floyd最短路计算,复杂度O(n^4),超时,确实没招,搜答案,发现了:

计蒜之道复赛A题  百度地图的实时路况(分治+floyd)

计蒜客 百度地图的实时路况

       看了半天才整明白,其思想是减少不必要的重复计算,Floyd算法是将每个点依次加入路径中进行计算最短路,题目中是求依次去掉一个点时其它任意两点最短路之和,如果枚举,那么就是每次去掉一个点,对剩余点Floyd求最短路,这其实会造成很大的浪费,比如你在去掉第一个点和第二个点时,floyd算法中依次将除了这两个点之外的其余点纳入求最短路就是重复了一次,因此可以将重复的工作结果先保存下来,下次用时不用再次计算,这就是分治的思想。

       具体到本题,可以将所有点分两部分,前半部分加入进行Floyd最短路计算后,将这部分结果保存用于后半部分的求解,若要对前半部分求解,需后半部分加入Floyd最短路后保存结果供前半部分使用;然后对此递归分治,直到只剩一个点时,其余点都已加入进行了Floyd最短路计算,相当于去掉这个点求Floyd,按题目中公式求和即可。

       借鉴前人代码,重新整理了下,更清晰些:

#include <iostream>
#include <stdlib.h>
using namespace std;


int iMem(0);
long long iFluid(0);    // 防止溢出;
int num(0);


struct dist
{
 long long distance[301][301];
 void addPointCal(int k)
 {
  for(int i=1; i<=num; i++)
   for(int j=1; j<=num; j++)
   {
    if(distance[i][k]!=-1&&distance[k][j]!=-1)
     if(distance[i][j]==-1||distance[i][j]>distance[i][k]+distance[k][j])
      distance[i][j]=distance[i][k]+distance[k][j];
   }
 };
};
dist floydDist[10];


void divideConquer(int iRes,int left,int right)
{
//cout<<"divideConquer("<<iRes<<","<<left<<","<<right<<")  ";
 if(left==right)
 {
  for(int i=1; i<=num; i++)
  {
   if(i==left) continue;
   for(int j=1; j<=num; j++)
   {
    if(j==left) continue;
    iFluid+=floydDist[iRes].distance[i][j];
   }
  }
//cout<<"divideConquer("<<iRes<<","<<left<<","<<right<<") return"<<endl;
  return;
 }


 int mid=(left+right)>>1;
 iMem=iRes+1;
 floydDist[iMem]=floydDist[iRes];
 for(int i=left; i<=mid; i++)
  floydDist[iMem].addPointCal(i);
//cout<<"floydDist["<<iMem<<"]:add("<<left<<","<<mid<<")  "<<endl;
 divideConquer(iMem,mid+1,right);


 floydDist[iMem]=floydDist[iRes];
 for(int i=mid+1; i<=right; i++)
  floydDist[iMem].addPointCal(i);
//cout<<"floydDist["<<iMem<<"]:add("<<mid+1<<","<<right<<")  "<<endl;
 divideConquer(iMem,left,mid);


 iMem--;
//cout<<"divideConquer("<<iRes<<","<<left<<","<<right<<") return"<<endl;
}


int main()
{
 cin>>num;
 for(int i=1; i<=num; i++)
  for(int j=1; j<=num; j++)
   cin>>floydDist[0].distance[i][j];


 divideConquer(0,1,num);
 cout<<iFluid;
 return iFluid;
}

 

 

0 0
原创粉丝点击