题目:
http://poj.org/problem?id=2449
题意:
给定一个图,求从一点到另一点的第k短路
思路:
用
A∗
搜索写的。我们知道,对于
A∗
搜索,有估价函数
f(n)=g(n)+h(n)
,其中
f(n)
是当前点的估值,通过估值大小我们决定搜索进行的次序,
g(n)
是走到当前点已经有的花费,
h(n)
是当前点到目标点的花费的估值,是最重要的部分。
h(n)
越小,运行的越慢,如果
h(n)=0
,则只有
g(n)
,此时的
A∗
就变成了
Dijkstra
算法。 如果
h(n)
比
g(n)
大很多,则
A∗
就变成了
BFS
。
h(n)
过大时无法保证求得的是最短路径,设
h′(n)
为实际的当前点到目标点的花费,那么符合条件的
A∗
搜索应该满足
h(n)<=h′(n)
。
在本题中,我们建图时同时建一个反向图,然后从终点求一次最短路,得出终点到每个点的最短距离存到
dis
数组中,可以认为这个
dis
就是估价函数中的
h
函数,这是没有问题的。进行
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> pii;
const int N = 1000 + 10, INF = 0x3f3f3f3f;
struct edge
{
int to, cost, next;
}g[N*200];
struct node
{
int f, g, v;//f,g是估价函数中相应的值
friend bool operator< (node a, node b)
{
if(a.f != b.f) return a.f > b.f;
else return a.g > b.g;
}
};
int cnt, head[N], rhead[N];
int dis[N];
bool vis[N];
void add_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
void radd_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = rhead[v], rhead[v] = cnt++;
}
void dijkstra(int s, int t)
{
priority_queue<pii, vector<pii>, greater<pii> > que;
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
que.push(pii(0, s)), dis[s] = 0;
while(! que.empty())
{
int v = que.top().second; que.pop();
if(vis[v] == true) continue;
vis[v] = true;
for(int i = rhead[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(dis[u] > dis[v] + g[i].cost)
{
dis[u] = dis[v] + g[i].cost;
que.push(pii(dis[u], u));
}
}
}
}
int a_star(int s, int t, int k)
{
if(s == t) k++;
if(dis[s] == INF) return -1;
int tot = 0;
priority_queue<node> que;
node e;
e.v = s, e.g = 0, e.f = e.g + dis[s];
que.push(e);
while(! que.empty())
{
node p = que.top(); que.pop();
if(p.v == t)
{
if(++tot == k) return p.g;
}
for(int i = head[p.v]; i != -1; i = g[i].next)
{
e.v = g[i].to, e.g = p.g + g[i].cost, e.f = e.g + dis[e.v];
que.push(e);
}
}
return -1;
}
int main()
{
int n, m;
while(~ scanf("%d%d", &n, &m))
{
cnt = 0;
memset(head, -1, sizeof head);
memset(rhead, -1, sizeof rhead);
int a, b, c;
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c);
radd_edge(b, a, c);
}
int s, t, k;
scanf("%d%d%d", &s, &t, &k);
dijkstra(t, s); //求出从终点t到所有点的最短路
int ans = a_star(s, t, k);
printf("%d\n", ans);
}
return 0;
}