题目连接 传送门
分析:
参考传送门
前言:最短路算法是我们非常熟悉的了。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
#include
#include
#include
using namespace std;
const int maxn=1010,ed=10010;
int n,m,s,en,k,t;
int dis[maxn],times[maxn];
bool vis[maxn];
struct edge
{
int to,next,val;
}e[ed],eo[ed];
int head[maxn],heado[maxn];
struct anode
{
int p,g,h;
bool operator < (anode x) const
{
return x.h+x.g q;
void add(int cnt,int u,int v,int w)
{
e[cnt].next=head[u];
e[cnt].to=v;
e[cnt].val=w;
head[u]=cnt;
}
void addo(int cnto,int u,int v,int w)
{
eo[cnto].next=heado[u];
eo[cnto].to=v;
eo[cnto].val=w;
heado[u]=cnto;
}
void dij(int s,int e)
{
memset(vis,0,sizeof(vis));
memset(dis,127,sizeof(dis));
int mi;
dis[e]=0;
for(int i=1;i<=n;i++)
{
mi=0;
for(int j=1;j<=n;j++)
if(!vis[j]&&dis[mi]>dis[j]) mi=j;
vis[mi]=1;
for(int x=heado[mi];x;x=eo[x].next)
dis[ eo[x].to ]=min(dis[ eo[x].to ],dis[mi]+eo[x].val);
}
}
int astar(int s,int en)
{
anode t1,tmp;
memset(times,0,sizeof(times));
while(!q.empty()) q.pop();
t1.g=t1.h=0;
t1.p=s;
q.push(t1);
while(!q.empty())
{
t1=q.top();
q.pop();
times[t1.p]++;
if(times[t1.p]<=k&&t1.h>t) return -1;
if(times[t1.p]==k&&t1.p==en) return t1.h;
if(times[t1.p]>k) continue;
for(int i=head[t1.p];i;i=e[i].next)
{
tmp.p=e[i].to;
tmp.g=dis[e[i].to];
tmp.h=e[i].val+t1.h;
q.push(tmp);
}
}
return -1;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
scanf("%d%d%d%d",&s,&en,&k,&t);
memset(head,0,sizeof(head));
memset(heado,0,sizeof(heado));
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(i,x,y,z);
addo(i,y,x,z);
}
dij(s,en);
if(s==en) k++;
int ans=astar(s,en);
if(ans==-1||ans>t) printf("Whitesnake!\n");
else printf("yareyaredawa\n");
}
return 0;
}