[POJ 2449] Remmarguts' Date [A*搜索]

来源:互联网 发布:移动4g网络模式选择 编辑:程序博客网 时间:2024/05/21 08:36

求第k最短路问题,有向图,数据范围:点数不超过1000,边数不超过10^5,k不超过1000

题目需要注意的地方:虽然题目描述说的是求T到S的第k短路,但是实际上根据样例可以知道我们应该求从S到T的第k短路...另外如果S==T,最初的那个不用走就到了的是不算做一条路的..也就是说必须要走

算法:首先用原图的反向图计算每个点到T的最短路,然后使用A*算法,估价函数f(i)=g(i)+h(i),其中h(i)是从i到T的最短路长度,g(i)是目前从起点到i所搜索出来的某条路径的长度。使用优先队列,每次选取f(i)最小的点进行扩展。一个点可以在同一时刻在队列里出现多次,因为他们代表不从S按照不同的路径到达这个点。

空间复杂度:队列的大小不会超过nk,因为如果某个点在队列里累计出现了k+1次,那么从k+1次的那个点向外扩展到t,最少是第k+1短路而不是k短路

时间复杂度:会遍历到从S点开始所有长度小于第k短路的有希望到达T点的路,若这些路上的点的和为t,则复杂度为tlogt。因为每个点都不会进入队列超过k次,所以复杂度不会超过nklog(nk)

需要注意的地方:只有出队序列才是满足估价函数逐渐增长的,不可以按照入队序列查看,T点的第k次出队才是第k短路。如果某个点不能够到达T点,那么我们不会将其加入优先队列。若队列为空,则不存在第k短路。

#include <cstdio>#include <cstring>#include <queue>using namespace std;struct Node {int fe,v;bool visited;};struct Edge {int ne,t,v;};struct Que {int i,f;Que() {}Que(int ii,int ff) {i=ii;f=ff;}friend bool operator < (const Que &a,const Que &b) {return a.f>b.f;}};int n,m,k,s,t,p,q,ansk;Node a[1001];Edge b[100001];Node c[1001];Edge d[100001];int que[1001];priority_queue <Que> e;void putedge(int x,int y,int z) {b[p].ne=a[x].fe;b[p].t=y;b[p].v=z;a[x].fe=p;d[p].ne=c[y].fe;d[p].t=x;d[p].v=z;c[y].fe=p;p++;}void spfa(int s,int t,Node a[],Edge b[]) {int i,j;p=q=0;a[s].v=1;a[s].visited=true;que[q++]=s;while (p!=q) {i=que[p];for (j=a[i].fe;j;j=b[j].ne) {if (a[b[j].t].v==0||a[b[j].t].v>a[i].v+b[j].v) {a[b[j].t].v=a[i].v+b[j].v;if (!a[b[j].t].visited) {a[b[j].t].visited=true;que[q]=b[j].t;q=(q+1)%1001;}}}a[i].visited=false;p=(p+1)%1001;}}int astar(int s,int t,Node a[],Edge b[]) {e.push(Que(s,a[s].v));while (!e.empty()) {int i=e.top().i;int v=e.top().f;//printf("%d %d\n",i,v-a[i].v);e.pop();if (i==t) {ansk++;if (k==ansk) return v;}for (int j=a[i].fe;j;j=b[j].ne) {if (a[b[j].t].v>=0) {e.push(Que(b[j].t,v+b[j].v+a[b[j].t].v-a[i].v));//printf("Push: %d %d\n",b[j].t,v-a[i].v+b[j].v);}}}return -1;}int main() {int i,x,y,z;scanf("%d%d",&n,&m);p=1;ansk=0;memset(a,0,sizeof(a));memset(c,0,sizeof(c));for (i=0;i<m;i++) {scanf("%d%d%d",&x,&y,&z);putedge(x,y,z);}scanf("%d%d%d",&s,&t,&k);if (s==t) k++;spfa(t,s,c,d);for (i=1;i<=n;i++) a[i].v=c[i].v-1;//for (i=1;i<=n;i++) printf("%d ",a[i].v);//printf("\n");if (a[s].v!=-1) {printf("%d\n",astar(s,t,a,b));} else printf("-1\n");return 0;}


0 0
原创粉丝点击