码迷,mamicode.com
首页 > 其他好文 > 详细

次短路 + 第K短路 模版

时间:2014-09-03 00:13:55      阅读:568      评论:0      收藏:0      [点我收藏+]

标签: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) 为当前从sp所走的路径的长度,h (p)为从点pt的最短路的长度,则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次出队,则当前路径的长度就是st的第K短路的长度,算法结束。否则,遍历与p项链的所有的边,将扩展出的到p的邻接点信息加入到优先队列。

   注意:当s = =t时需要计算K+1短路,以为st这条距离为0的路不能算在这K短路中,这时只需将K1后再求第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来测试模版,需要记住是要加两条边,正向和反向边。

 

  

 

次短路 + 第K短路 模版

标签:style   blog   io   使用   strong   ar   for   文件   art   

原文地址:http://www.cnblogs.com/Potato-lover/p/3952526.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!