poj2449 Remmarguts' Date(第k短路问题)(A*+spfa/dijkstra)

思路来源

https://blog.csdn.net/berrykanry/article/details/78345894(通俗易懂解释好评)

https://www.cnblogs.com/yyf0309/p/8438849.html(可惜看不懂可持久化可并堆)

题意

给定一个图,求第k短路,

相同长度不同路径的路被认为是不同的路,

若不存在输出-1。

题解

我才不会说我八数码题tleMLE了两天后补了一下A*算法又被安利来看这个破题

以终点为S进行dijkstra/spfa,

(具体实现可以建反向图)

然后得到了真实的评估函数h(n)的表, 

这样我到了一个点,就知道已走路g(n)+前方最短路h(n)这条路的cost,

把它记为截止到该点的理想最短路。

显然,我们从起点dis[n]即最短路开始延展,

相当于bfs,由起点转向其一步可达点,

即由最短路,转向了后续状态可能换了一条边的最短路。

后者是实际意义上的次短,第三短等等等…

而没换边的路,被加进优先队列里之后,

由于其距离小,还应处在队顶的位置,只是其截止点往后推了一个,

若不存在环,最终所有点的截止点都会被推到终点,

而我们只需要这其中的前k个。

而由于优先队列按距离排序,

当其到达终点的时候,对终点计贡献,

说明这些路是截止到终点的,长度严格递增的路。

当计到第k时,即为起点可达终点的k短路。

这个题,引发了我深深的感慨。

在人生之路上,当你还在为自己的前途备一个list,

记录第一志愿,第二志愿,……,第k志愿并在线为其比较的时候,

早就有人已经洞若观火,知道自己第一志愿应该报哪,

并且,为了选择第k志愿,明明知道最短路在哪,

不惜比照着自己已经打好的dijkstra表,

开始往那些非最短路的地方瞎走???

瞎走一步,啊,这次走到了次短路,加到队列里,

瞎走两步…瞎走k步,啊终于找到了我要的k短路

高考空了50分 终于考上了理想第k大学 既视感

代码

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10; 
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int n,m,s,t,k;
int head[1005],cnt,rehead[1005],qq[5005];
bool vis[1005];
int dis[1005];
struct edge{int to,nex,w;}e[100005],re[100005];
struct node
{
   int g;//当前已走 
   int f;//总 
   int id;//节点号 
   node(int a,int b,int c):g(a),f(b),id(c){
   }
};
bool operator>(node a,node b)
{
	if(a.f!=b.f)return a.f>b.f;
	return a.g>b.g;
}
priority_queue<pii,vector<pii>,greater<pii> >q;
priority_queue<node,vector<node>,greater<node> >p; 
void init()
{ 
	mem(head,-1);
	cnt=0;
	mem(rehead,-1);
	mem(vis,0);
}
void add(int u,int v,int w)
{
	e[cnt].to=v;//u->v
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
	re[cnt].to=u;//v->u
	re[cnt].w=w;
	re[cnt].nex=rehead[v];
	rehead[v]=cnt++;
}

void spfa(int src)
{
    for(int i = 1; i <= n; i++) dis[i] = INF;
    mem(vis,0);
    int h = 0, t = 1;
    qq[0] = src;
    dis[src] = 0;
    while(h < t)
    {
        int u = qq[h++];
        vis[u] = 0;
        for(int i = rehead[u] ; i != -1; i = re[i].nex)
        {
            int v = re[i].to;
            int w = re[i].w;
            if(dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                if(!vis[v])
                {
                    qq[t++] = v;
                    vis[v] = 1;
                }
            }
        }
    }
}
int astar(int s,int t)
{
	int num=0;
	if(s==t)k++;//注意这里,我们把s->s视作为0的最短路
	if(dis[s]==INF)return -1;
	while(!p.empty())p.pop();
	p.push(node(0,dis[s],s));//以t为视角的距离 
	while(!p.empty())
	{
		node tmp=p.top();
		p.pop();
		int g=tmp.g,f=tmp.f,u=tmp.id;
		if(u==t)
		{
		 num++; 
		 if(num==k)return g;
	    }
		for(int j=head[u];~j;j=e[j].nex)
		{
			int v=e[j].to,w=e[j].w;
			p.push(node(g+w,g+w+dis[v],v));
		}
	}
	return -1;
}
int main()
{    
    while(~scanf("%d%d",&n,&m))
    {
    init();
    rep(i,0,m-1)
    {
    	int u,v,w;
    	scanf("%d%d%d",&u,&v,&w);
    	add(u,v,w);
    }
    scanf("%d%d%d",&s,&t,&k);
    spfa(t);//对终点dijkstra
	printf("%d\n",astar(s,t));
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/83117480