首先分享一个我学习的博客文章:
看着他的题解学会了k短路。。%%%
然后我就大致说一说k短路的求法吧。。
首先我们来看看A*。
A*,启发式搜索,是一种较为有效的搜索方法。
我们在搜索的时候,很多时候在当前状态,已经不是最优解了,但是我们却继续求解;
这个就是暴力搜索浪费时间的原因。
我们在有些时候,往往可以根据一些信息推断出继续搜索是一种劣解,
所以如果能够判断出来的话,就可以不继续了,以达到节省运行时间的目的。
来看一题很经典的例题:BZOJ 1085。
1085: [SCOI2005]骑士精神
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2276 Solved: 1312
[ Submit ][ Status ][ Discuss ]
Description
在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑
士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空
位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步
数完成任务。
Input
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑
士,*表示空位。两组数据之间没有空行。
Output
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
Sample Input
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Sample Output
-1
HINT
Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 29710 | Accepted: 8068 |
Description
"Prince Remmarguts lives in his kingdom UDF – United Delta of Freedom. One day their neighboring country sent them Princess Uyuw on a diplomatic mission."
"Erenow, the princess sent Remmarguts a letter, informing him that she would come to the hall and hold commercial talks with UDF if and only if the prince go and meet her via the K-th shortest path. (in fact, Uyuw does not want to come at all)"
Being interested in the trade development and such a lovely girl, Prince Remmarguts really became enamored. He needs you - the prime minister's help!
DETAILS: UDF's capital consists of N stations. The hall is numbered S, while the station numbered T denotes prince' current place. M muddy directed sideways connect some of the stations. Remmarguts' path to welcome the princess might include the same station twice or more than twice, even it is the station with number S or T. Different paths with same length will be considered disparate.
Input
The last line consists of three integer numbers S, T and K (1 <= S, T <= N, 1 <= K <= 1000).
Output
Sample Input
2 2
1 2 5
2 1 4
1 2 2
Sample Output
14
这题待会儿要写题解,,算了还是写一遍吧(我帅)
题意就是:n个点,m条边,每条给出有向边并带有权值,给出start,end和k,求s~t所有路径中的第k短路。
没错这就是一道模板题目。。
我们来审视一下k短路的问题求解:
我们知道,可以暴力搜索,然后统计到第k短即可。
显然暴力是远远不行的。
另外,我们求最短路有许多优秀算法:dijkstra,SPFA……可以把最短路问题和k短路问题连接起来吗?
我们尝试一下A*。另f(x)是某k短路径的近似长度:
f(x)=g(x)+h(x)
f(x)就是路径的长度,g(x)是估价函数,我们选择x~end的最短路径(这个后面会解释);
h(x)是实际长度,start~x的总路径长。
那么我们优先访问f(x)更加小的点:因为它更可能成为最短,再第二短,再……
如果end被访问了k次了,那么目前得到的值f(x)就是k短路的长度。
现在可能还比较朦胧,我们进一步解释:
1.到底如何求k短路的?
我们考虑,要求k短路,要先求出最短路/次短路/第三短路……/第(k-1)短路,然后访问到第k短路。
接下来的方法就是如此操作的。
2.f(x)的意义?
我们得到的f(x)更小,优先访问这个f(x)的点。
我们可以定义一组数{p,g,h},p是某一个点,g是估价,h是实际,那么g+h更小的点p会优先访问。
为什么呢?因为假设我们求出了w短路,接下来要求(w+1)短路,就要求最小的另一条路径。
应该易理解。
3.为什么选择最短路来估价?
很简单的选择,我们既然要求最短了,当然是找最短路。
事实上这不是我们的初衷,但是有了“先求(k-1)短路”的概念后,这么理解也可以了。
4.实现
实现是比较简单的。
如何预处理出g(x)呢?显然,将所有边反向,然后求end到所有点的单源最短路径就好了。
接下来的启发式搜索可以简单解决。
事实上,就是在暴力搜索的基础上增加了启发式搜索:往一个最优的点的地方走。
另外还是要专来一篇这题blog的QAQ
关于上题目的程序:
(跑得有点慢。。300+ms。)
(大部分借鉴开头说的blog的程序)
//#include<bits/stdc++.h>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
Point=1005,
Edges=100005;
int n,m,start,end,kth;
int dist[Point],times[Point];
bool vis[Point];
struct Edge{
int to,next,val;
}E[Edges],Eopp[Edges]; //Eopp means Eopposite
int head[Point],head_opp[Point];
struct A_Star_node{
int p,g,h;
bool operator < (A_Star_node x)const{
return x.g+x.h<g+h;
}
}; //means point and a_Star:f(x)=g(x)+h(x);
priority_queue<A_Star_node>Q;
inline void add(int Ecnt,int u,int v,int w){
E[Ecnt].next=head[u];
E[Ecnt].to=v;
E[Ecnt].val=w;
head[u]=Ecnt;
}
inline void add_opposite(int EoppCnt,int u,int v,int w){
Eopp[EoppCnt].next=head_opp[u];
Eopp[EoppCnt].to=v;
Eopp[EoppCnt].val=w;
head_opp[u]=EoppCnt;
}
void dijkstra(int s,int e){
memset(vis,0,sizeof(vis));
memset(dist,127,sizeof(dist));
int mini; dist[e]=0;
for (int i=1;i<=n;i++){
mini=0;
for (int j=1;j<=n;j++)
if (!vis[j] && dist[mini]>dist[j]) mini=j;
vis[mini]=1;
for (int x=head_opp[mini];x;x=Eopp[x].next)
dist[Eopp[x].to]=min(dist[Eopp[x].to],dist[mini]+Eopp[x].val);
}
}
int A_Star(int s,int e){
A_Star_node t1,tmp;
memset(times,0,sizeof(times));
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]==kth && t1.p==e) return t1.h+t1.g;
if (times[t1.p]>kth) continue;
for (int i=head[t1.p];i;i=E[i].next){
tmp.p=E[i].to;
tmp.g=dist[E[i].to];
tmp.h=E[i].val+t1.h;
Q.push(tmp);
}
}
return -1;
}
int main(){
n=read(),m=read(),kth=read(),start=read(),end=read();
int x,y,z;
memset(head,0,sizeof(head));
memset(head_opp,0,sizeof(head_opp));
for (int i=1;i<=m;i++){
x=read(),y=read(),z=read();
add(i,x,y,z);
add_opposite(i,y,x,z);
}
dijkstra(start,end);
if (start==end) kth++;
int ans=A_Star(start,end);
if (ans==-1) puts("No");
else printf("%d\n",ans);
return 0;
}