【POJ】2449 Remmarguts' Date k短路(最短路径+A*)

来源:互联网 发布:大数据的4v特征变化快 编辑:程序博客网 时间:2024/06/06 05:53

题目传送门

题目大意就是给出起点s,终点t和一个参数k,以及一张图,问s到t间的k短路。

对于所有k短路问题,我们都可以用最短路+A*的方法来解决。

首先,我们根据输入数据建两张图:一张是和输入数据边的方向相同的正图,另一张是和输入数据边的方向相反的反图。

我们对反图以终点t为起点做一遍最短路(我用的是SPFA),可以得到所有点到终点t的最短距离。

然后从起点s开始做一遍A*,第k次遍历到终点t时的路径长度就是答案。

其中我们定义A*的估价函数f(i)=g(i)+h(i),h(i)的大小就是最短路得出来的节点i到终点t的最短路径长度,g(i)是原点s到节点i的实际距离。

为了使f较小的节点会被较早的扩展,保持BFS的特性,我们可以用一个优先队列来维护,以f为关键字。

因为我们每次取队头节点p,也就是整个队列中f最小的节点,所以当前状态是队列里所有节点p的关键字f最小的状态,在把所有与节点p相连的节点插入队列,相当于枚举了所有节点的关键字f。每次取的都是所有状态中关键字f最小的状态,保证了每次枚举到的节点都是以最短路径扩展而来。因此可以推出用A*的方法得到的k短路是成立的。

最后一次搜到终点t时,g(t)就是答案。


注意:如果s=t,则++k。这个……我也不知道为何……

附上AC代码:

#include <cstdio>#include <vector>#include <queue>#include <cstring>using namespace std;struct note{int d,w;};vector <note> z[1010],f[1010];int n,m,x,y,w,s,t,k,dis[1010];queue <int> que;bool b[1010];struct node{int v,g,f;bool operator < (const node lyf) const {if (lyf.f==f) return lyf.g<g;return lyf.f<f;}};priority_queue <node> dui;void spfa(){for (int i=1; i<=n; ++i) dis[i]=2e9;que.push(t),b[t]=1,dis[t]=0;while (!que.empty()){int p=que.front();que.pop(),b[p]=0;for (int i=0; i<f[p].size(); ++i)if (dis[f[p][i].d]>dis[p]+f[p][i].w){dis[f[p][i].d]=dis[p]+f[p][i].w;if (!b[f[p][i].d]){b[f[p][i].d]=1;que.push(f[p][i].d);}}}return;}int astar(){if (s==t) ++k;if (dis[s]==2e9) return -1;int c=0;dui.push((node){s,0,dis[s]});while (!dui.empty()){node p=dui.top();dui.pop();if (p.v==t) ++c;if (c==k) return p.g;for (int i=0; i<z[p.v].size(); ++i)dui.push((node){z[p.v][i].d,p.g+z[p.v][i].w,p.g+z[p.v][i].w+dis[z[p.v][i].d]});}return -1;}int main(void){scanf("%d%d",&n,&m);for (int i=1; i<=m; ++i){scanf("%d%d%d",&x,&y,&w);z[x].push_back((note){y,w});f[y].push_back((note){x,w});}scanf("%d%d%d",&s,&t,&k);spfa();printf("%d",astar());return 0;}


0 0
原创粉丝点击