K短路——A*算法

A*

简介:

  • A A ∗ (Astar),是一种启发式搜索,也是 bfs b f s 的特例。准确说, bfs b f s 是盲目的搜索。
  • 那么 A A ∗ 就是让决策优化,
  • 实际上,就是预处理终点到起点的最短路,再在起点到终点时判断第 K K 短路。
  • 这是一个非常实用的解决第K短路问题的算法。

常规操作:
- 先预处理出终点到起点(反图)的最短路(SPFA,Dijs)
- 再通过优先队列来对起点到终点的路径判断第 K K 短路

Code(模板):

int S,T,K;

struct edge{
    int to,cost;
};
vector<edge>E[N],G[N];

int dis[N];
bool vis[N];
queue<int>Q;

void SPFA(){//反图 T->S 
    while(!Q.empty())Q.pop();
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f3f3f3f,sizeof(dis));

    Q.push(T);
    vis[T]=1;
    dis[T]=0;

    while(!Q.empty()){
        int x=Q.front();Q.pop();
        vis[x]=0;
        for(int i=0;i<(int)G[x].size();++i){
            int y=G[x][i].to;
            if(dis[y]>dis[x]+G[x][i].cost){
                dis[y]=dis[x]+G[x][i].cost;
                if(!vis[y]){
                    vis[y]=1;
                    Q.push(y);
                }
            }
        } 
    }
}

struct Anode{
    int to,d,all;
    bool operator<(const Anode &_)const{
        return all==_.all?d>_.d:all>_.all;
    }
};
priority_queue<Anode>Star;

int Astar(){//S->T
    if(dis[S]==0x3f3f3f3f)return -1;
    if(S==T)K++;
    int cnt=0;

    while(!Star.empty())Star.pop();

    Star.push((Anode){S,0,dis[S]});

    while(!Star.empty()){
        Anode now=Star.top();Star.pop();
        int x=now.to;
        if(x==T){
            cnt++;
            if(cnt==K)return now.d;
        }
        for(int i=0;i<(int)E[x].size();i++){
            int y=E[x][i].to;
            Star.push((Anode){y,now.d+E[x][i].cost,now.d+E[x][i].cost+dis[y]});
        }
    }
    return-1;
}

Summary:

  • A算法针对于第 K K 短路非常实用,但其本身还是有缺陷,可以被卡成Θ(nm)

    • 对于较大的数据,还是左偏树可并堆解决的了… 但写法还是非常方便的。
    • 例题:POJ2449 Remmarguts’ Date

      Description:

      n个点,m条边的有向图,求s到t的第k短路。

      Solution:

      • A*算法解决第k短路裸题。

      Code:

      #include<cstdio>
      #include<iostream>
      #include<algorithm>
      #include<cstring>
      #include<vector>
      #include<queue>
      #include<cstdlib>
      using namespace std;
      #define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
      #define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;i++)
      #define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
      #define db double
      #define LL long long 
      #define INF 0x3f3f3f3f
      #define MINF 0xc0c0c0c0
      #define inf 0x3f3f3f3f3f3f3f
      #define Sz(a)sizeof(a)
      #define mcl(a,b)memset(a,b,Sz(a))
      #define mcp(a,b)memcpy(a,b,Sz(b))
      #define pb push_back
      #define fi first
      #define se second
      template<class T>inline bool chkmin(T&x,T y){return y<x?x=y,1:0;}
      template<class T>inline bool chkmax(T&x,T y){return x<y?x=y,1:0;}
      inline LL Max(LL x,LL y){return x>y?x:y;}
      inline LL Min(LL x,LL y){return x<y?x:y;}
      typedef pair<int,int>PII;
      
      #define N 1002
      #define M 500002
      
      int n,m;
      int S,T,K;
      
      int qwq1,qwq2,head1[N],head2[N];
      struct edge{
          int to,next,cost;
      }E[M],G[M];
      void addedge(int x,int y,int z){
          E[qwq1]=(edge){y,head1[x],z};head1[x]=qwq1++;
          G[qwq2]=(edge){x,head2[y],z};head2[y]=qwq2++;
      }
      
      int dis[N];
      bool vis[N]; 
      queue<int>Q;
      
      struct Anode{
          int to,d,all;
          bool operator<(const Anode &_)const{
              return all==_.all?d>_.d:all>_.all;
          }
      };
      priority_queue<Anode>Star;
      
      void SPFA(){
          while(!Q.empty())Q.pop();
          mcl(dis,INF);
          mcl(vis,0);
      
          Q.push(T);
          dis[T]=0;
          vis[T]=1;
      
          while(!Q.empty()){
              int x=Q.front();Q.pop();
              vis[x]=0;
              for(int i=head2[x];~i;i=G[i].next){
                  int y=G[i].to;
                  if(chkmin(dis[y],dis[x]+G[i].cost)){
                      if(!vis[y]){
                          vis[y]=1;
                          Q.push(y);
                      }
                  }
              }
          }
      }
      
      int Astar(){
          int cnt=0;
          if(S==T)K++;
          if(dis[S]==INF)return-1;
      
          while(!Star.empty())Star.pop();
      
          Star.push((Anode){S,0,dis[S]});
      
          while(!Star.empty()){
              Anode now=Star.top();Star.pop();
              int x=now.to;
              if(x==T){
                  cnt++;
                  if(cnt==K)return now.d;
              }
              for(int i=head1[x];~i;i=E[i].next){
                  int y=E[i].to;
                  Star.push((Anode){y,now.d+E[i].cost,now.d+E[i].cost+dis[y]});
              }
          }
          return-1;
      }
      void Clear(){
          qwq1=qwq2=0;
          mcl(head1,-1);
          mcl(head2,-1);
      }
      
      int main(){
      //  printf("sz=%d\n",(Sz(E)*2+Sz(dis)*2+Sz(Star)+Sz(Star))/1024/1024);
          while(~scanf("%d%d",&n,&m)){
      
              Clear();
      
              REP(i,1,m){
                  int a,b,c;
                  scanf("%d%d%d",&a,&b,&c);
                  addedge(a,b,c);
              }
              scanf("%d%d%d",&S,&T,&K);
              SPFA();
              printf("%d\n",Astar());
          }
          return 0;
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值