Made In Heaven
问题分析
题意:求
1
1
到的第
k
k
短的路径长度,如果超过输出
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
的实际距离,还有一个对于任意顶点
n
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
的比较,我们在执行算法时,
g(n)
g
(
n
)
就很大程度影响了我们的算法效率,我们实现函数
g(n)
g
(
n
)
时,可以将原图的边反向,把终点改成源点,跑一次
dijkstra
d
i
j
k
s
t
r
a
,算出每一个点
u
u
到的距离,即
g(n)
g
(
n
)
。当
g(n)>T
g
(
n
)
>
T
时,我们应忽略此节点,不去拓展。
代码
#include <bits/stdc++.h>
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<node> 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; 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> 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; i<len; i++)
{
node v = adj[u.id][i];
if(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; i<Maxn; i++) adj[i].clear(),_adj[i].clear();
scanf("%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;
}