最短路
Posted fuyun_boy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路相关的知识,希望对你有一定的参考价值。
背景
鹰最骄傲的就是翱翔,但是鹰们互相都很嫉妒别的鹰比自己飞的快,更嫉妒其他的鹰比自己飞行的有技巧。于是,他们决定举办一场比赛,比赛的地方将在一个迷宫之中。
题目
这些鹰的起始点被设在一个N*M矩阵的左下角map[1,1]的左下角。终点被设定在矩阵的右上角map[N,M]的右上角,有些map[i,j]是可以从中间穿越的。每一个方格的边长都是100米。如图所示:
没有障碍,也没有死路。这样设计主要是为了高速飞行的鹰们不要发现死路来不及调整而发生意外。潘帕斯雄鹰冒着减RP的危险从比赛承办方戒备森严的基地中偷来了施工的地图。但是问题也随之而来,他必须在比赛开始之前把地图的每一条路都搞清楚,从中找到一条到达终点最近的路。(哈哈,笨鸟不先飞也要拿冠军)但是此鹰是前无古鹰,后无来鹰的吃菜长大的鹰--菜鸟。他自己没有办法得出最短的路径,于是紧急之下找到了学OI的你,希望找到你的帮助。
输入
首行为n,m(0<n,m<=100000),第2行为k(0<k<=1000)表示有多少个特殊的边。以下k行为两个数,i,j表示map[i,j]是可以直接穿越的。
输出
仅一行,1,1-->n,m的最短路径的长度,四舍五入保留到整数即可
样例输入
3 2
3
1 1
3 2
1 2
样例输出
383
这个题目很容易想到是DP,没错,这个题目就是DP,但是以最标准的思想列出方程
f[i,j]表示在map[i,j]到map[1,1]的最小值
则:f[i,j]=min{f[i-1,j],f[i,j-1]}+1 如果存在特殊边再这样处理一下
f[i,j]=min{f[i,j],f[i-1,j-1]+sqrt(2)}
ans=round(f[n,m])即可
但是这样就有两个问题,一个是时间复杂度问题O(nm)在这个题目中是TLE的
另一个问题是空间复杂度问题O(nm)的空间在这个题目中是MLE的
那让我们换一个思路,如果能走特殊路,必然要走特殊路,这个是显然的。
从map[i,j]到map[i+1,j+1]最多有三条路,其中的两条长度为2,而如果有特殊路,其长度为sqrt(2)
而这里k只有1000
在这1000个路中寻找最长的可走路线
即lis的变形问题。这个复杂度是O(k^2)。
实现方式,首先字典排序,把边的顺序处理好,然后lis,最后利用数学推导在取x条特殊路的时候所走的路线即可。
详细的细节参考code
还有一种思路就是利用这k个点做最短路径。这个也是可以的算法同样为O(k^2)。在题目审核的时候某位题审就是这样用spfa AC的。
这个题目是比较标准的DP了,同时也可以用图论做。并且题目本身并不难。本题其实有一个提示,M、N都是非常大的数,如果从m、n去考虑只有O(M+N)的算法能够AC,但是K十分的小,这就是提示,让大家往K的复杂度上想。和noip2006 2一样,很多大牛当时都看做tree-dp来做,其实看到附件的个数并不是很多,就可以作为背包搞定了,也减少了很多的编写复杂度。
此题考察:对算法的设计 DP 最短路
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 #define MAX 1005 6 #define mp make_pair 7 #define ft first 8 #define sd second 9 10 int f[MAX],M,N,K,temp; 11 pair<int ,int> a[MAX]; 12 13 void init() 14 { 15 int x,y; 16 cin>>N>>M; 17 cin>>K; 18 for(int i=1;i<=K;i++){ 19 scanf("%d%d%*c",&x,&y); 20 a[i]=mp(x,y); 21 } 22 for(int i=1;i<=K-1;i++){ 23 for(int j=1;j<=K-i;j++){ 24 if( a[j].first>a[j+1].first || a[j].second>a[j+1].second ){ 25 x=a[j].ft;y=a[j].sd; 26 a[j]=mp( a[j+1].ft,a[j+1].sd ); 27 a[j+1]=mp( x,y ); 28 } 29 } 30 } 31 } 32 33 void DP() 34 { 35 for(int i=1;i<=K;i++){ 36 temp=0; 37 for(int j=0;j<=i;j++){ 38 //printf("%d %d %d %d\n", a[j].ft,a[j].sd,a[i].ft,); 39 if( a[j].ft<a[i].ft && a[j].sd<a[i].sd && f[j]+1>temp ){ 40 // cout<<"!!!"; 41 temp=f[j]+1; 42 } 43 } 44 f[i]=temp; 45 } 46 temp=0; 47 for(int i=1;i<=K;i++) 48 if( f[i]>temp ) 49 temp=f[i]; 50 } 51 52 int main() 53 { 54 freopen("fly.in","r",stdin); 55 freopen("fly.out","w",stdout); 56 long long int x; 57 init(); 58 DP(); 59 // for(int i=1;i<=K;i++)printf("%d ",f[i]); 60 //printf("%d \n",temp); 61 x=int(((M+N)-2*temp+sqrt(2)*temp)*1000); 62 if((x%10)>=5)printf("%d",x/10+1); 63 else printf("%d",x/10); 64 system("pause"); 65 return 0; 66 }
以上是关于最短路的主要内容,如果未能解决你的问题,请参考以下文章