K短路(A*+SPFA)

 

 

 

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 const int MAX_V = 1100;
  8 const int MAX_E = 110000;
  9 const int INF = 0x3f3f3f3f;
 10 
 11 struct ENode
 12 {
 13     int to;
 14     int w;
 15     int Next;
 16 };
 17 ENode edegs[MAX_E];
 18 ENode edegs1[MAX_E]; //存反图;
 19 int Head[MAX_V], Head1[MAX_V], tnt, tnt1;
 20 void Add_ENode (int a, int b, int w)
 21 {
 22     ++ tnt;
 23     edegs[tnt].to= b;
 24     edegs[tnt].w= w;
 25     edegs[tnt].Next= Head[a];
 26     Head[a]= tnt;
 27 //    ++ tnt;  //无向图
 28 //    edegs[tnt].to= a;
 29 //    edegs[tnt].w= w;
 30 //    edegs[tnt].Next= Head[b];
 31 //    Head[b]= tnt;
 32 }
 33 void Add_ENode1 (int a, int b, int w)
 34 {
 35     /**建反向图*/
 36     ++ tnt1;
 37     edegs1[tnt1].to= b;
 38     edegs1[tnt1].w= w;
 39     edegs1[tnt1].Next= Head1[a];
 40     Head1[a]= tnt1;
 41 //    ++ tnt1;  //无向图
 42 //    edegs1[tnt1].to= a;
 43 //    edegs1[tnt1].w= w;
 44 //    edegs1[tnt1].Next= Head1[b];
 45 //    Head1[b]= tnt1;
 46 }
 47 
 48 int Dis[MAX_V];
 49 bool visit[MAX_V]; //是否已经遍历过;
 50 int que[MAX_V]; // 模拟队列;
 51 int outque[MAX_V]; //记录每个点出队列的次数,防止有负边,保证无负边的图可以省略;
 52 bool SPFA(int s, int n)
 53 {
 54     /**SPFA处理反向图,预处理出Dis[]*/
 55     /*s:起点; n:点的总数*/
 56     int iq; //队列中元素个数;
 57     memset(Dis, INF, sizeof(Dis));
 58     memset(visit, false, sizeof(visit));
 59     memset(outque, 0, sizeof(outque));
 60     iq= 0;
 61     que[iq ++]= s;
 62     visit[s]= true;
 63     Dis[s]= 0;
 64     int i= 0;
 65     while (i< iq)
 66     {
 67         int u= que[i];
 68         visit[u]= false;
 69         outque[u] ++;
 70         if (outque[u]> n) return false; //当一个点进出队列超过n 次,必然有负边存在;
 71 
 72         for (int k= Head1[u]; k!= -1; k= edegs1[k].Next)
 73         {
 74             /*bfs,和Dijkstra相似*/
 75             int v= edegs1[k].to;
 76             if (Dis[v]> Dis[u]+ edegs1[k].w)
 77             {
 78                 Dis[v]= Dis[u]+ edegs1[k].w;
 79                 if (! visit[v])
 80                 {
 81                     visit[v]= true;
 82                     que[iq ++]= v;
 83                 }
 84             }
 85         }
 86         i ++;
 87     }
 88     return true;
 89 }
 90 
 91 struct Node
 92 {
 93     int from;
 94     int g; //g表示到当前点的路径长度
 95     int f; //f=g+dis dis表示当前点到终点的最短路径,即之前的预处理
 96     bool operator < (const Node &r) const
 97     {
 98         if (r.f== f) return r.g- g< 0;
 99         return r.f- f< 0;
100     }
101 };
102 int A_star (int s, int t, int n, int k)
103 {
104     Node e, ne;
105     int cnt= 0;
106     priority_queue<Node> que;
107     if (s== t) k ++;
108     if (Dis[s]== INF) return -1;
109     e.from= s;
110     e.g= 0;
111     e.f= e.g+ Dis[e.from];
112     que.push(e);
113     while (! que.empty())
114     {
115         e= que.top();
116         que.pop();
117         if (e.from== t) cnt ++;
118         if (cnt== k) return e.g;
119         for (int i= Head[e.from]; i!= -1; i= edegs[i].Next)
120         {
121             ne.from= edegs[i].to;
122             ne.g= e.g+ edegs[i].w;
123             ne.f= ne.g+ Dis[ne.from];
124             que.push(ne);
125         }
126     }
127     return -1;
128 }
129 
130 void into()
131 {
132     /**初始化*/
133     memset(Head,-1,sizeof(Head));
134     memset(Head1,-1,sizeof(Head1));
135     tnt= -1; tnt1= -1;
136 }
137 
138 int main()
139 {
140     int n, m, k;
141     int a, b, w;
142     while (~ scanf("%d %d %d", &n, &m, &k))
143     {
144         into();
145         for (int i= 0; i< m; i ++)
146         {
147             scanf("%d %d %d", &a, &b, &w);
148             Add_ENode(a, b, w);
149             Add_ENode1(b, a, w);  //建反图
150         }
151         SPFA(n, n); //处理出从终点到其他点的最短路径距离;
152         int far= A_star(1, n, n, k);
153         printf("%d\n", far);
154     }
155     return 0;
156 }
View Code

 

posted @ 2019-07-18 10:22  egoist的翻绳游戏  阅读(211)  评论(0编辑  收藏  举报