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

来源:互联网 发布:分期网站源码 编辑:程序博客网 时间:2024/05/22 17:43

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;  }  
阅读全文
0 0