标签:style blog io 使用 strong ar for 文件 art
虽然从字面上看,次短路和第2短路是一样的。但是我在题目中遇到的却不是这样的。
在有些题目中,需要判断次短路是否存在。比如说,u、v之间只有一条路径。那么只有最短路。次短路是不存在的。这时候,解题方法是先求出最短路,然后枚举删除最短路径中的边,然后求最小值。题目可以看poj3986。
第K短路的实现是 SPFA + A* 算法。
A*算法通过一个估价函数f(h)来估计途中的当前点p到终点的距离,并由此决定它的搜索方向,当这条路径失败时,它会尝试其他路径。对于A*,估价函数 = 当前值 + 当前位置到终点的距离, 即f (p) = g (p) + h (p) ,每次扩展估计函数值最小的一个。对于K短路算法来说,g (p) 为当前从s到p所走的路径的长度,h (p)为从点p到t的最短路的长度,则f (p)的意义就是从s按照当前路径走到p后再走到终点t一共至少要走多远。
具体实现步骤:
使用链式前向星来存储图, 由于需要预处理所有的点到终点T的最短路径,就需要将图G中所有的边反响得到G1再从终点T做单源最短路径,所以实际上是两张图。
1、将有向图的所有边反向。以T(终点)为源点,求解T到所有点的最短距离。这一步可以用Dijkstra 或者 SPFA算法。
2、新建一个优先队列,将源点S加入到队列中。
3、从优先队列中弹出f (p)最小的p,如果点p就是t ,则计算t出队的次数,如果当前为T的第K次出队,则当前路径的长度就是s到t的第K短路的长度,算法结束。否则,遍历与p项链的所有的边,将扩展出的到p的邻接点信息加入到优先队列。
注意:当s = =t时需要计算K+1短路,以为s到t这条距离为0的路不能算在这K短路中,这时只需将K加1后再求第K短路即可。
如果u、v之间只有一条路径,那么k短路与最短路的值是一样的。还得知道的是,如果u、v之间如果存在一个圈,那么K+1短路比K短路就要多这个圈的边权的和。
K短路的模版如下,时间复杂度不确定,不过能知道已经很高效了。可以去用poj2449测试,只要加头文件和主函数就可以了。
const int N = 1010, M=100010;
const int INF = 0x3f3f3f3f;
struct node
{
int to, w, next;
};
node edge[M],edge1[M];
int head[N], dist[N], outq[N], head1[N], tot;
bool vis[N];
bool SPFA(int s, int n )
{
int i,k;
for(i=0;i<=n;i++) dist[i]=INF;
memset(vis,0,sizeof(vis));
memset(outq,0,sizeof(outq));
queue<int > q;
while(!q.empty()) q.pop();
vis[s]=1;
dist[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
outq[u]++;
if(outq[u]>n) return 0 ;
k=head1[u];
while(k>=0)
{
if(dist[edge1[k].to]-edge1[k].w>dist[u])
{
dist[edge1[k].to]=dist[u]+edge1[k].w;
if(!vis[edge1[k].to])
{
vis[edge1[k].to]=1;
q.push(edge1[k].to);
}
}
k=edge1[k].next;
}
}
return 1;
}
struct Node1
{
int to;
int g,f;
bool operator<(const Node1 &r) const
{
if(r.f==f) return r.g<g;
return r.f<f;
}
};
int a_star(int start, int End, int k,int n)
{
Node1 e,ne;
int cnt=0;
priority_queue<Node1> que;
while(!que.empty()) que.pop();
if(start==End) k++;
if(dist[start]==INF) return -1;
e.to=start;
e.g=0;
e.f=e.g+ dist[e.to];
que.push(e);
while(!que.empty())
{
e= que.top();
que.pop();
if(e.to==End) cnt++;
if(cnt==k) return e.g;
for(int i=head[e.to];i!=-1;i=edge[i].next)
{
ne.to=edge[i].to;
ne.g=e.g+ edge[i].w;
ne.f=ne.g+ dist[ne.to];
que.push(ne);
}
}
return -1;
}
void addedge(int i,int j,int w)
{
edge[tot].to=j;
edge[tot].w=w;
edge[tot].next=head[i];
head[i]=tot++;
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(head1,-1,sizeof(head1));
}
枚举 + 最短路 实现次短路重要的一步是要用一个前驱来记录最短路径。还需要对属于最短路径的边标记。
const int N = 1010, M=100010;
const int INF = 0x3f3f3f3f;
struct node
{
int u,to, w, next,flag;
};
node edge[M];
int head[N], dist[N], outq[N];
bool vis[N];
int tot,flag,path[N];
bool SPFA(int s, int n )
{
int i,k;
for(i=0;i<=n;i++) dist[i]=INF;
memset(vis,0,sizeof(vis));
memset(outq,0,sizeof(outq));
queue<int > q;
while(!q.empty()) q.pop();
vis[s]=1;
dist[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
outq[u]++;
if(outq[u]>n) return 0 ;
k=head[u];
while(k>=0)
{
if(edge[k].flag&&dist[edge[k].to]-edge[k].w>dist[u])
{
dist[edge[k].to]=dist[u]+edge[k].w;
if(!flag) path[edge[k].to]=k;
if(!vis[edge[k].to])
{
vis[edge[k].to]=1;
q.push(edge[k].to);
}
}
k=edge[k].next;
}
}
return 1;
}
void addedge(int i,int j,int w)
{
edge[tot].u=i;
edge[tot].to=j;
edge[tot].w=w;
edge[tot].flag=1;
edge[tot].next=head[i];
head[i]=tot++;
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(path,-1,sizeof(path));
}
可以用poj3986来测试模版,需要记住是要加两条边,正向和反向边。
标签:style blog io 使用 strong ar for 文件 art
原文地址:http://www.cnblogs.com/Potato-lover/p/3952526.html