Remmarguts's Date

第一场区域赛选拔赛的题目,虽然是板子题,但这个板子我是第一次敲......不仅板子是第一次敲,k短路也是第一次敲......

题意就是让你求一张图上从起点S到终点T的k短路。这里我们使用A*来进行求解。构造一个函数\(h[x] = f[x] + g[x]\),其中f[x]表示当前搜索时的代价,也就是边权;g[x]表示的是从当前点到终点的最短路,这可以通过以T为起点反向dijkstra得到。对于终点T,当它第k次从队首中被拿出来时,说明此时已经找到了k短路。事实上这里的A*只是使用估价函数优化了的BFS,是简化了的A*,真正的A*还需要维护OpenList和CloseList两个集合。

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <list>
#include <set>
#include <utility>
#include <map>
#include <stack>
#include <cctype>
#include <string>
#include <queue>
#define mst(a,b) memset((a),(b),sizeof(a))
#define debug printf("debug\n")
#define INF 0x3f3f3f3f
#define IOS std::ios::sync_with_stdio(false)
const int maxn=1e5+5;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct edge{
    int u;
    int v,c;
    int nxt;
    int nxt1;
    edge(){}
    edge(int u,int v,int c)
        :u(u),v(v),c(c){
        }
};
edge es[100005];
int head[1010];
int head1[1010];
int tot_e;        //总边数 
int st,ed,k;
int n,m;
int dis[maxn];
bool vis[maxn];
struct pro{
    int v,c;
    pro(){}
    pro(int v,int c)
        :v(v),c(c){
        }
    /*
    h[x] = f[x] + g[x]
    其中f[x]表示当前搜索时的代价,也就是边权
    g[x]表示的是从当前点到终点的最短路,可以
    反向跑一遍dij得到 
    */
    bool operator<(const pro& pa) const{
        return c+dis[v]>pa.c+dis[pa.v];        //估价函数 
    }
};
void init()
{
    mst(head,-1);mst(head1,-1);
    tot_e=0;
}
void add(int u,int v,int c)
{
    //链式前向星加边
    es[tot_e]=edge(u,v,c);
    es[tot_e].nxt=head[u];head[u]=tot_e;
    es[tot_e].nxt1=head1[v];head1[v]=tot_e++;
}
priority_queue<pro> que;
void dijkstra(int start)
{
    mst(vis,0);
    for(int i=1;i<=n;i++)    dis[i]=INF;
    dis[start]=0;
    while(!que.empty())    que.pop();
    que.push(pro(start,0));
    while(!que.empty()){
        pro cur=que.top();
        que.pop();
        if(vis[cur.v])    continue;
        vis[cur.v]=1;
        for(int i=head1[cur.v];i!=-1;i=es[i].nxt1){
            if(dis[es[i].u]>dis[cur.v]+es[i].c){
                dis[es[i].u]=dis[cur.v]+es[i].c;
                que.push(pro(es[i].u,0));
            }
        }
    }
}
int Astar(int start)        //其实这里只是经过了启发式优化的BFS 
{
    while(!que.empty())    que.pop();
    que.push(pro(start,0));
    while(!que.empty()){
        pro cur=que.top();
        que.pop();
        if(cur.v==ed){
            if(k>1)    k--;        //终点第k次入队时,说明找到了k短路 
            else    return cur.c;
        }
        for(int i=head[cur.v];i!=-1;i=es[i].nxt)
            que.push(pro(es[i].v,cur.c+es[i].c));
    }
    return -1;
}
int main()
{
    while(scanf("%d %d",&n,&m)!=EOF){
        init();
        int u,v,c;
        for(int i=0;i<m;i++){
            scanf("%d %d %d",&u,&v,&c);
            add(u,v,c);
        }
        scanf("%d %d %d",&st,&ed,&k);
        dijkstra(ed);
        if(dis[st]==INF){
            printf("-1\n");
        }else{
            if(st==ed)    k++;
            int ans=Astar(st);
            printf("%d\n",ans);
        }
    }
    return 0;
}