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

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

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

P=1x,y,zn,xy,yzd(x,y,z)

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

输入格式

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

接下来输入 n 行,每行输入 n 个整数。第 i 行第 j 个数 Gi,j(1Gi,j10000;Gi,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,但是就是求不经过这个点的时候,所有点之间两两的最短路,正常方法应该是枚举不经过的点然后floyd,然后就是 O(n4) 的复杂度,然后就GG了,但是考虑到每个不经过的点的时候,其实有很多的两点之间的距离并不会改变,就是有重复计算的,所以就是要想办法优化复杂度。
这里用到的是巧妙的分治,solve(l,r)表示当前要计算这个区间内的点不被经过时的最短路,然后考虑 [l,mid] 里这些点如果经过的话,那么可以用来计算 [mid+1,r] 这些区间里的答案,如果 [mid+1,r] 这些区间里的点经过的话,那么可以用来计算前半个区间的答案,考虑 [l,r] 的时候,其实前面的区间的点和后面区间的点都已经计算进去了,然后你进去前半段,就把后半段区间的点也算进去,如果考虑后半段,就把前面的点算进去,就是大概这么一个思路,其实实现起来还是比较麻烦的,逻辑上不太容易想清楚。
我仍需努力啊这种题就GG了。


代码:

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;
#define   MAX           200005
#define   MAXN          6005
#define   maxnode       15
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
//const double inf   = 1e18;
const double eps   = 1e-8;
const LL    mod    = 1e9+7;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
    char c;
    while((c=getchar())<'0' || c>'9');
    x=c-'0';
    while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
 }
/*****************************************************/

int dp[20][305][305];
LL ans;
int n;
void cdq(int num,int l,int r){
    if(l==r){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i!=l&&j!=l&&i!=j){
                    if(dp[num][i][j]>=INF) ans-=1;
                    else ans+=dp[num][i][j];
                }
            }
        }
        return;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++) dp[num+1][i][j]=dp[num][i][j];
    }
    int mid=(l+r)/2;
    for(int k=l;k<=mid;k++){
        for(int i=1;i<=n;i++){
            if(dp[num+1][i][k]==-1) continue;
            for(int j=1;j<=n;j++){
                if(dp[num+1][k][j]==-1) continue;
                dp[num+1][i][j]=min(dp[num+1][i][j],dp[num+1][i][k]+dp[num+1][k][j]);
            }
        }
    }
    cdq(num+1,mid+1,r);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++) dp[num+1][i][j]=dp[num][i][j];
    }
    for(int k=mid+1;k<=r;k++){
        for(int i=1;i<=n;i++){
            if(dp[num+1][i][k]==-1) continue;
            for(int j=1;j<=n;j++){
                if(dp[num+1][k][j]==-1) continue;
                dp[num+1][i][j]=min(dp[num+1][i][j],dp[num+1][i][k]+dp[num+1][k][j]);
            }
        }
    }
    cdq(num+1,l,mid);
}
int main(){
    cin>>n;
    ans=0;
    mem(dp,INF);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&dp[0][i][j]);
            if(dp[0][i][j]==-1) dp[0][i][j]=INF;
        }
    }
    cdq(0,1,n);
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
A*算法是一种常见的启发式搜索算法,用于寻找最短路径。而Floyd算法则是一种动态规划算法,用于求解所有点对之间的最短路径。在实际应用中,我们可以将A*算法和Floyd算法结合起来,以提高A*算法的搜索效率。 下面给出Matlab实现A*算法并用Floyd算法进行优化的步骤: 1. 定义地图 首先,我们需要定义地图,即描述节点之间的关系。可以使用一个邻接矩阵来表示地图。假设地图中有n个节点,邻接矩阵A的大小为n×n,A(i,j)表示节点i到节点j的距离,如果i和j之间没有边相连,则A(i,j)的值为无穷大。 2. 定义启发函数 启发函数用于估计从当前节点到目标节点的距离。在A*算法中,我们使用曼哈顿距离或欧几里得距离作为启发函数。这里我们使用曼哈顿距离: function h=heuristic(start,goal) h=abs(start(1)-goal(1))+abs(start(2)-goal(2)); end 其中,start和goal是起点和终点的坐标。 3. 定义A*算法 A*算法的核心是一个开放列表(open list)和一个关闭列表(closed list)。开放列表存储待搜索的节点,关闭列表存储已经搜索过的节点。 function [path, cost]=Astar(start,goal,A) n=size(A,1); %节点个数 closed=zeros(n,1); %关闭列表 gscore=inf(n,1); %起点到各节点的实际距离 fscore=inf(n,1); %起点到各节点的估计距离 gscore(start)=0; fscore(start)=heuristic(start,goal); open=start; while ~isempty(open) [~,current]=min(fscore(open)); %当前节点 if current==goal %到达终点 path=reconstruct_path(start,goal); cost=gscore(goal); return end open(current)=[]; %从开放列表中删除 closed(current)=1; %加入关闭列表 for neighbor=find(A(current,:)) %遍历邻居 if closed(neighbor) %已经搜索过 continue end tentative_gscore=gscore(current)+A(current,neighbor); %计算g值 if ~ismember(neighbor,open) %新节点 open=[open neighbor]; elseif tentative_gscore>=gscore(neighbor) %已经有更优的路径 continue end %更新节点信息 came_from(neighbor)=current; gscore(neighbor)=tentative_gscore; fscore(neighbor)=gscore(neighbor)+heuristic(neighbor,goal); end end %无法到达终点 path=[]; cost=inf; end 其中,reconstruct_path(start,goal)函数用于重构路径。 4. 定义Floyd算法 Floyd算法的核心是一个动态规划转移方程: D(i,j)=min(D(i,k)+D(k,j),D(i,j)) 其中,D(i,j)表示节点i到节点j的最短路径,k是一个中间节点。 function [D,path]=Floyd(A) n=size(A,1); %节点个数 D=A; path=cell(n,n); for i=1:n for j=1:n if A(i,j)<inf path{i,j}=[i j]; end end end for k=1:n for i=1:n for j=1:n if D(i,j)>D(i,k)+D(k,j) D(i,j)=D(i,k)+D(k,j); path{i,j}=[path{i,k} path{k,j}(2:end)]; end end end end end 5. 优化A*算法 我们可以将A*算法的搜索范围缩小到起点和终点之间的距离加上起点到终点的最短路径。 function [path,cost]=Astar_optimized(start,goal,A) [D,~]=Floyd(A); %计算最短路径 max_distance=sum(D(start,goal))+heuristic(start,goal); n=size(A,1); %节点个数 closed=zeros(n,1); %关闭列表 gscore=inf(n,1); %起点到各节点的实际距离 fscore=inf(n,1); %起点到各节点的估计距离 gscore(start)=0; fscore(start)=heuristic(start,goal); open=start; while ~isempty(open) [~,current]=min(fscore(open)); %当前节点 if current==goal %到达终点 path=reconstruct_path(start,goal); cost=gscore(goal); return end open(current)=[]; %从开放列表中删除 closed(current)=1; %加入关闭列表 for neighbor=find(A(current,:)) %遍历邻居 if closed(neighbor) %已经搜索过 continue end tentative_gscore=gscore(current)+A(current,neighbor); %计算g值 if ~ismember(neighbor,open) %新节点 open=[open neighbor]; elseif tentative_gscore>=gscore(neighbor) %已经有更优的路径 continue end %更新节点信息 came_from(neighbor)=current; gscore(neighbor)=tentative_gscore; fscore(neighbor)=gscore(neighbor)+heuristic(neighbor,goal); end %优化搜索范围 if fscore(current)>max_distance break end end %无法到达终点 path=[]; cost=inf; end 至此,我们已经完成了Matlab实现A*算法并用Floyd算法进行优化的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值