hdu6181-启发式搜索A*|次短路模板|最短路枚举-Two Paths

69 篇文章 0 订阅
58 篇文章 0 订阅

acm.hdu.edu.cn/showproblem.php?pid=6181
我是用次短路板子做的。。初始化得多点不然得超时。
①求次短路的思路是维护到达x点的最小距离和次小距离。(dij和spfa应该都可以,都做一下板子)
② 用A*,即启发式搜索,先求出F(X)即x点到目的点的代价,在求S(x),即初始点到x点的代价,然后找第k小的。用muliset或者优先队列都行,(multiset写了好一会。。)
③ 求出最短路后,枚举。。这个我没敢弄,因为怕超时。O(VE)
* 我A*的理解:一般的搜索都是闭着眼搜索,随便搜索,枚举所有的状态,有的花费巨大且是坑,但是也要试一遍。效率不高。
而A*则预先计算当前状态到目的状态的花费,找最小的试,
贼好。正面计算 初始点到当前状态的话费时,像bfs,但是比bfs高效的原因就是因为前面的就记录(不记录爆搜的话mle)
这里写图片描述
先计算了D,在遍历F,

#include <bits/stdc++.h>
using namespace std;
/*    multiset 或者优先队列,都是可以的,,好像qwq
*/
/* 
*/
typedef long long ll;
typedef pair<ll,int> pii;
const long long INF=1e14;
const int maxn=1e5;
struct Node{
      int to;ll w;
       Node(){};
       Node(int _a,ll _b){to=_a;w=_b;};
};
ll dis[maxn];
struct qNode{
      int to;
      ll w;
      qNode(){};
      qNode(ll  _a,int _b){to=_b;w=_a;};
      friend bool  operator <(qNode a,qNode b){
             return a.w+dis[a.to]<b.w+dis[b.to];// 返回最小的。这个很重要,A*的重点(敲屏幕)
      }
};
//记录D(x)
vector<Node>G[maxn];
multiset<qNode>mul;
void add(int u,int v,long long w){
    G[u].push_back(Node(v,w));
    G[v].push_back(Node(u,w));
}
int k,m;
void init(){
     for(int i=0;i<maxn;i++)
         G[i].clear();
     mul.clear();
}
void dij(int st){
    priority_queue<pii,vector<pii>,greater<pii> >q;
    for(int i=0;i<maxn;i++)
        dis[i]=INF;
    dis[st]=0;
    q.push(make_pair(0,st));
    while(!q.empty()){
          pii u=q.top();
          //cout<<u.second<<"!!"<<u.first<<endl;
          q.pop();
          for(int i=0;i<G[u.second].size();i++){

              ll d=G[u.second][i].w+u.first;
               int to=G[u.second][i].to;
               if(d<dis[to]){
                  dis[to]=d;
                  q.push(make_pair(dis[to],to));
                  //cout<<d<<"juli"<<endl;
                 // cout<<G[u.second][i].w<<"jjjjl"<<endl;
               }
          }
    }
}
void  a_star(int st){
    mul.insert(qNode(0,st));
    k--;
    while(!mul.empty()){
         qNode u=*mul.begin();
         mul.erase(mul.begin());
         if(u.to==m){
            if(k) k--;
            else
                {cout<<u.w<<endl;return;}
         }
         for(int i=0;i<G[u.to].size();i++){
                //cout<<G[u.to][i].w+u.w<<endl;
             int to=G[u.to][i].to;
             mul.insert(qNode(u.w+G[u.to][i].w,to));
         }
         //cout<<mul.size()<<"@@@"<<endl;
    }
}
/*void a_sta(int st){
     priority_queue<qNode>q;
     q.push(qNode(0,st));
    k--;
     while(!q.empty()){
          qNode u=q.top();
          q.pop();
          if(u.to==m){
            if(k)k--;
            else {printf("%lld\n",u.w);return;}
          }
          for(int i=0;i<G[u.to].size();i++){
              ll d=G[u.to][i].w+u.w;
              int to=G[u.to][i].to;
              q.push(qNode(d,to));
          }
     }

}*/
int main(){
    int t,a,b,n;
    ll c;
    scanf("%d",&t);
    while(t--){
         init();
         scanf("%d%d",&m,&n);
          for(int i=0;i<n;i++){
             scanf("%d%d%lld",&a,&b,&c);
             add(a,b,c);
          }
          dij(m);
          k=2;
          //for(int i=1;i<=m;i++)
             //cout<<i<<" "<<dis[i]<<endl;
          a_star(1);
    }
 return 0;
}

次短路板子(dij逼格高,试着求了一下第三短哈哈)

#include <bits/stdc++.h>
using namespace std;
/* 次短路的做法,
   ① 次短路模板,维护两个值。
   ② 两次最短路。
   ③ A*算法
*/
const int maxn=1e5+5;
const long long INF=1e14;
typedef long long ll;
struct Node
{    int to,val;
     Node(){};
     Node(int _a,int _b){to=_a,val=_b;};
};
vector<Node>G[maxn];
ll dis[maxn];
ll dis2[maxn];
ll dis3[maxn];
void add(int a,int b,ll w){
     G[a].push_back(Node(b,w));
     G[b].push_back(Node(a,w));
}
void dij(int st){
    for(int i=0;i<maxn;i++){
        dis[i]=INF;
        dis2[i]=INF; //初始化
        dis3[i]=INF;
    }
    priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >q;
    dis[st]=0;
    q.push(make_pair(0,st));//入开头元素
    while(!q.empty()){
         pair<ll,int>u=q.top();
         //cout<<u.first<<endl;
         q.pop();
         if(dis2[u.second]<u.first) continue;
         for(int i=0;i<G[u.second].size();i++){
              ll d=G[u.second][i].val+u.first;
              int to=G[u.second][i].to;
              if(d<dis[to]){
                 swap(d,dis[to]);//最短的。
                q.push(make_pair(dis[to],to));
              }
               if(dis[to]<d&&dis2[to]>d){
                   swap(d,dis2[to]);
                q.push(make_pair(dis2[to],to));
                }
                /*if(dis3[to]>d&&dis2[to]<d&&dis[to]<d){
                    dis3[to]=d;
                    q.push(make_pair(dis3[to],to));

                }*/
         }
    }
}
void init(){
     for(int i=0;i<maxn;i++)
          G[i].clear();
}
int main()
{   int t,m,n,a,b;
    ll c;
    scanf("%d",&t);
    while(t--){
          scanf("%d%d",&m,&n);
          init();
          for(int i=0;i<n;i++){
              scanf("%d%d%lld",&a,&b,&c);
              add(a,b,c);
          }
          //puts("!!!!");
          dij(m);
          /*for(int i=1;i<=m;i++)
            cout<<dis[i]<<" "<<dis2[i]<<endl;*/
          printf("%lld\n",dis2[1]);
    }
    return 0;
}

暴力枚举最短路,大佬的代码,,,先贴了。。
我第一个思路也是这样,但是想的是,维护最短路径,然后每个节点枚举,,而不是这样全图暴力枚举,,只能说大佬。

#include <cstdio>  
#include <cstring>  
#include <queue>  
#include <algorithm>  
#include <iostream>  
using namespace std;  
typedef long long int ll;  
const int R = 100000+5;  
const int INF = 0x3f3f3f3f;  
int n,m;  
struct Node  
{  
    int v;  
    int w;  
    int next;  
}edge[R*2];  
int head[R];  
ll dist1[R];  
ll dist2[R];  
bool vis[R];  
int num;  
void init()  
{  
    num = 0;  
    memset(head,-1,sizeof(head));  
    for(int i = 1; i <= n; i++)  
        dist1[i] = dist2[i] = 1e16;  
}  

void add_edge(int u,int v,int w)  
{  
    edge[num].v = v;  
    edge[num].w = w;  
    edge[num].next = head[u];  
    head[u] = num++;  
}  
void SPFA(int u,ll *dist)  
{  
    int i,v,w;  
    queue<int> Q;  
    memset(vis,false,sizeof(vis));  
    dist[u] = 0;  
    vis[u] = true;  
    Q.push(u);  
    while(!Q.empty())  
    {  
        u = Q.front();  
        Q.pop();  
        vis[u] = false;  
        for(i=head[u];i!=-1;i=edge[i].next)  
        {  
            v = edge[i].v;  
            w = edge[i].w;  
            if(dist[v] > dist[u] + w)  
            {  
                dist[v] = dist[u] + w;  
                if(!vis[v])  
                {  
                    vis[v] = true;  
                    Q.push(v);  
                }  
            }  
        }  
    }  
}  
int main()  
{  
    int t;  
    scanf("%d",&t);  
    while(t--)  
    {  
        scanf("%d%d",&n,&m);  
        int i,j,u,v,w;;  
        init();  
        for(i=1;i<=m;i++)  
        {  
            scanf("%d%d%d",&u,&v,&w);  
            add_edge(u,v,w);  
            add_edge(v,u,w);  
        }  
        SPFA(1,dist1);  
        SPFA(n,dist2);  
        int flag = 0;  
        ll ans = 1e16;  
        for(i=1;i<=n;i++)  
        {  
            for(j=head[i];j!=-1;j=edge[j].next)  
            {  
                v = edge[j].v;  
                w = edge[j].w;  
                //cout<<i<<v<<endl;  
                ll tem = dist1[i] + dist2[v] + w;  
                //cout<<tem<<endl;  
                if(tem > dist1[n] && tem < ans)  
                {  
                    ans = tem;  
                }  
            }  
        }  
        printf("%I64d\n",ans);  
    }  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值