K短路 学习笔记

K短路,顾名思义,是让你求从$s$到$t$的第$k$短的路。

暴力当然不可取,那么我们有什么算法可以解决这个问题?

--------------------------

首先,我们要维护一个堆。

struct node
{
    int dist,pos;
    bool operator <(const node&x) const
    {
        return dist>x.dist;
    }
}
priority_queue<node> q;

这个堆是用来干什么的?

----------------------------------------------

这时候要提到一种新算法:A*算法。

估价函数:$f[i]=g[i]+h[i]$。其中,$g[i]$是从起点$s$走,按照这条路径到当前点已经走了多少路程,$h[i]$是当前点到终点$t$的最短路。

我们用之前开设的堆来维护这个估价函数,这样到达第k次终点$t$的路径即为所求。

Code(这里是[SDOI2010]魔法猪学院的A*算法):

void Astar(int kk)
{
    priority_queue<SKT> q;
    memset(vis,0,sizeof(vis));
    x.pos=1;x.dist=0.0;x.h=0.0;
    q.push(x);
    while(!q.empty())
    {
        int now=q.top().pos;double d=q.top().dist;double hh=q.top().h;q.pop();
        if (d>E) return;
        vis[now]++;
        if (now==n){ans++;E-=d;continue;}
        if (vis[now]>kk) continue;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            SKT Faker;
            Faker.pos=to;Faker.h=hh+edge[i].dis;Faker.dist=Faker.h+dis[to];
            q.push(Faker);
        }
    }
}

----------------------------------

每个点到终点$t$的最短路怎么求?很简单,我们只要在建图的时候再建一个反向图,从终点跑单源最短路径即可。

Code:

void spfa()
{
    for (int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;
    queue<int> q;
    q.push(n);dis[n]=0.0;vis[n]=1;
    while(!q.empty())
    {
        int now=q.front();q.pop();vis[now]=0;
        for (int i=Head[now];i;i=Edge[i].next)
        {
            int to=Edge[i].to;
            if (dis[to]>dis[now]+Edge[i].dis)
            {
                dis[to]=dis[now]+Edge[i].dis;
                if (!vis[to]) q.push(to),vis[to]=1;
            }
        }
    } 
}

----------------------------

例题:[USACO08MAR]Cow Jogging G

近乎于K短路的裸题,只需要注意$u$大于$v$即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1005;
const int maxm=20005;
int dis[maxn],vis[maxn];
int n,m,k;
struct SKT {
    int v;
    int dist;
    bool operator < (const SKT&p) const {
        return dist+dis[v]>p.dist+dis[p.v];
    }
};
SKT x;
struct Node
{
    int next,to,dis;
}edge[maxm],cont[maxm];
int heade[maxm],headc[maxm],cnt;
inline void add(int from,int to,int dis)
{
    edge[++cnt].next=heade[from];
    edge[cnt].to=to;
    edge[cnt].dis=dis;
    heade[from]=cnt;
    cont[cnt].next=headc[to];
    cont[cnt].to=from;
    cont[cnt].dis=dis;
    headc[to]=cnt;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void spfa()
{
    queue<int> q;
    for (int i=1;i<=n;i++) dis[i]=0x7fffffff;
    q.push(1);dis[1]=0;vis[1]=1;
    while(!q.empty())
    {
        int now=q.front();q.pop();vis[now]=0;
        for (int i=headc[now];i;i=cont[i].next)
        {
            int to=cont[i].to;
            if (dis[to]>dis[now]+cont[i].dis)
            {
                dis[to]=dis[now]+cont[i].dis;
                if (!vis[to]) q.push(to),vis[to]=1;
            }
        }
    }
}
void Astar()
{
    int ans=0;
    priority_queue<SKT> q;
    x.v=n;x.dist=0;
    q.push(x);
    while(!q.empty())
    {
        SKT now=q.top();q.pop();
        if (now.v==1) printf("%d\n",now.dist),++ans;
        if (ans==k) return;
        for (int i=heade[now.v];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (to<now.v)
            {
                SKT Faker=now;
                Faker.v=to;Faker.dist=now.dist+edge[i].dis;
                q.push(Faker);
            }
        }
    }
    while(ans<k) cout<<-1<<endl,++ans;
    return;
}
signed main()
{
    n=read(),m=read(),k=read();
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read(),z=read();
        if (x>y) add(x,y,z);
    }
    spfa();
    Astar();
    return 0; 
}

 

posted @ 2020-04-01 23:10  我亦如此向往  阅读(174)  评论(0编辑  收藏  举报