题意:求 1 1 到 n n 的第 k k 短的路径长度,如果超过 T T 输出 Whitesnake! W h i t e s n a k e ! ,否则输出 yareyaredawa y a r e y a r e d a w a 。
题解:这道题呢,核心就在于对于 A∗ A ∗ 算法的理解与应用。
这里不打算长述什么是 A∗ A ∗ 算法。
只需要知道 A∗ A ∗ 也是基于 bfs b f s 的就可以了,我们知道 bfs b f s 是针对每一个未访问的节点,用一个队列去扩展它,直到队列为空。但是 bfs b f s 是很傻的,只要对于未访问的节点,它都去拓展。 A∗ A ∗ 之所以更优秀是因为它更聪明,它有一个从起点到任意顶点 n n 的实际距离 g(n) g ( n ) ,还有一个对于任意顶点 n n 到目标顶点的估算距离 h(n) h ( n ) ,那么 A∗ A ∗ 就可以通过这两个函数去衡量优先拓展哪一个节点,我们称这个估算函数为 f(n)=h(n)+g(n) f ( n ) = h ( n ) + g ( n ) 。
对于 f(n) f ( n ) 估价函数的设计,大大影响了算法的效率。
其中,当 h(n)≠0 h ( n ) ≠ 0 时,我们一定可以找到最优解, h(n) h ( n ) 越小,需要拓展的节点就越多;但是当 h(n)=0 h ( n ) = 0 时,算法就变成了普通的 dijkstra d i j k s t r a ,因为没有了对于目标顶点的估算。其次,如果 g(n)=0 g ( n ) = 0 呢?此时算法是最快的,可以很快的找到最短路径,但是,我们对实际距离没有了确定的值,找到的路却不一定正确,就相当于我们跑普通的 bfs b f s 找到了目测的最短路却忽略了其中可能会有障碍物。
大致理解了 A∗ A ∗ 的估算函数就看代码吧~
这题有一个坑点,就是对于 T T 的比较,我们在执行 A∗ A ∗ 算法时, g(n) g ( n ) 就很大程度影响了我们的算法效率,我们实现函数 g(n) g ( n ) 时,可以将原图的边反向,把终点改成源点,跑一次 dijkstra d i j k s t r a ,算出每一个点 u u 到 t t 的距离,即 g(n) g ( n ) 。当 g(n)>T g ( n ) > T 时,我们应忽略此节点,不去拓展。
#include
using namespace std;
const int Maxn = 10010, INF = 1e9+7;
struct node {
int to,val;
node() {
}
node(int a,int b)
{
to = a; val = b;
}
};
vector adj[Maxn],_adj[Maxn];
bool vis[Maxn];
int dis[Maxn],n,m,k;
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; iif(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 pq;
int BFS(int s,int t,int limit)
{
while(!pq.empty()) pq.pop();
pq.push(Anode(0,dis[s],s));
int len,num;
num = 0;
while(!pq.empty())
{
Anode u = pq.top(); pq.pop();
if(u.id==t) ++num;
if(u.h > limit)
return -1;
if(num>=k) return u.h;
len = adj[u.id].size();
for(int i=0; iif(dis[v.to] > limit) //本题核心所在
continue;
pq.push(Anode(u.h+v.val,dis[v.to],v.to));
}
}
return -1;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int x,y,v,s,t,limit;
for(int i=0; iscanf("%d%d%d%d",&s,&t,&k,&limit);
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&x,&y,&v);
AddEdge(x,y,v);
}
if(s==t) k++;
Dijkstra(s,t);
int ans = BFS(s,t,limit);
if(ans > limit || ans == -1)
printf("Whitesnake!\n");
else{
printf("yareyaredawa\n");
}
}
return 0;
}