1. 程式人生 > >求圖的第K短路(A*演算法與最短路的應用)

求圖的第K短路(A*演算法與最短路的應用)

前言:最短路演算法是我們非常熟悉的了。Dijkstra,SPFA等單源最短路演算法是我們在競賽中常用的演算法。那麼,假如題目要求的不是最短的呢?

Question(1):給定一個圖,求次短路。

對於次短路,很容易想到在比較的時候進行處理。

設dis(u)為原點s到u的最短路徑,u為當前節點,v和u有邊相連。

x = dis[v] + f[u][v];

則對於最短路:if(dis[u] > x) dis[u] = x;

而對於次短路:

if(dis[u]>x) dis2[u]=dis[u],dis[u]=x;

else if(dis2[u]>x) dis2[u]=x;

所以,對於次短路,只需加多一個數組即可。

那麼,K短路呢?

Question(2):給定一個圖,求第K短路。

對於這個問題,可以用A*演算法+Dijkstra解決。

先了解一下A*演算法:

A*演算法是一種典型的啟發式搜尋演算法。定義:

h*(s)為狀態s到目標的距離

h(s)為估價函式,狀態s到目標距離的下界,即h(s)<=h*(s)

g(s)為到達狀態s所需的代價

f(s)為s的啟發函式。有f(s) = h(s) + g(s)。

那麼,對於本題:h(s)就是源點到s的距離,g(s)為到終點t的實際距離。

如果能求出g,那麼,當A*搜尋了終點k次後,當前的h就為答案。

求函式g的方法:因為g(s)為到終點t的實際距離,所以,可以把原圖的邊反向後,把終點改成源點,跑一次Dijkstra,算出每一個點u到t的距離,就是所求的g。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <stack>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define Maxn 10010
#define INF 1000000000

struct node{
	int to,val;
	node() {}
	node(int a,int b)
	{
		to = a; val = b;
	}
};

vector<node> adj[Maxn],_adj[Maxn];

int n,m,k;
bool vis[Maxn];
int dis[Maxn];

void AddEdge(int x,int y,int val)
{
	adj[x].push_back(node(y,val));
	_adj[y].push_back(node(x,val));//把圖反向
}
void Dijkstra(int s,int t)
{
	priority_queue<int , vector<int> , greater<int> > q;
	while(!q.empty()) q.pop();
	
	for(int i=1;i<=n;i++) vis[i] = false,dis[i] = INF;
	vis[t] = true; dis[t] = 0; q.push(t);
	
	int u,len;
	while(!q.empty())
	{
		u = q.top();  q.pop();
		len = _adj[u].size();
		for(int i=0;i<len;i++)
		{
			node v = _adj[u][i];
			if(dis[v.to] > dis[u] + v.val)
			{
				dis[v.to] = dis[u] + v.val;
				if(!vis[v.to])
				{
					q.push(v.to);
					vis[v.to] = true;
				}
			}
		}
		vis[u] = false;
	}
}

struct Anode{
	int h,g,id;
	Anode(int a,int b,int c) {h=a; g=b; id=c;}
	bool operator < (Anode a) const
	{
		return h+g > a.h+a.g;
	}
};

priority_queue<Anode> Q;

int Astar(int s,int t)//A*演算法過程
{
	while(!Q.empty()) Q.pop();
	Q.push(Anode(0,dis[s],s));
	
	int len,num;
	num = 0;
	while(!Q.empty())
	{
		Anode u = Q.top(); Q.pop();
		if(u.id==t) ++num;
		if(num>=k) return u.h;
		
		len = adj[u.id].size();
		for(int i=0;i<len;i++)
		{
			node v = adj[u.id][i];
			Q.push(Anode(u.h+v.val,dis[v.to],v.to));
		}
	}
	
	return -1;//不能連通或者沒有第K短路
}

int main()
{
	while(scanf("%d%d",&n,&m)!=-1)
	{
		for(int i=0;i<Maxn;i++) adj[i].clear(),_adj[i].clear();
		int x,y,v,s,t;
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&x,&y,&v);
			AddEdge(x,y,v);
		}
		scanf("%d%d%d",&s,&t,&k);
		if(s==t) k++;
		Dijkstra(s,t);
		printf("%d\n",Astar(s,t));
	}
	return 0;
}