题意:
求从一个点s 到 一点 e 经过 n 条边的最短路经是多少(可以有重边)
贴一个floyd算法讲解:
http://blog.csdn.net/niushuai666/article/details/6772706
以前一直没仔细想过floyd算法,觉得很简单,今天做这题的时候,看网上的报告都有一句:floyd是每次使用一个中间点k去更新i,j之间的距离,那么更新成功表示i,j之间恰有一个点k时的最短路,如果做N - 1次floyd那么不就是i,j之间借助N - 1 个点时的最短路了。看了很久不明白为什么。也对floyd的最外围的那个k<n产生了疑惑。后来突然想到了,floyd每次更新的都是本身,假如k=3时,dis[1][5]借助dis[1][3]和dis[3][5]成为最短路。不需要去知道1,3之间有多少个点,因为前面已经求出,,(dp?)只知道这一次求出的dis[1][5]多加了一个3这个点。
回到这题,floyd算法是对自身矩阵更新,而这道题却是更新到另一个矩阵上,所以不会出现刚更新过的值又来更新。。例如下面代码的b.mat[1][3] c.mat[3][5]就分别代表上面的dis[1][3],dis[3][5].我们不需要知道tmp.mat[1][5]已经有的点个数。(即已经更新的次数。)只知道,这次更新会加入一个3到他们中间。所以更新k-1次就行。
1 void floyd(Mat b,Mat c) 2 { 3 tmp.init(); 4 for(int k=1;k<=cnt;k++) 5 for(int i=1;i<=cnt;i++) 6 for(int j=1;j<=cnt;j++) 7 { 8 if(b.mat[i][k] <0 || c.mat[k][j] <0) 9 continue; 10 if(tmp.mat[i][j]<0 || tmp.mat[i][j] > b.mat[i][k] + c.mat[k][j] ) 11 tmp.mat[i][j] = b.mat[i][k] + c.mat[k][j]; 12 } 13 }
注意的地方:
1、N次floyd可以用倍增思想加速,就是自底向上的二分。类似求矩阵快速幂(M67大牛)。
2、这里还有一点要注意,T的范围是(2~100),所以最多顶点只有200,而顶点标号的范围却(1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000)。这样我们可以将编号离散化。
3、最后一点这个题的inf要开很大。开始开的是0x5fffffff还是wa了。后来看了某个博客 可以把inf定义为-1。就没这个问题了。值得学习。
ps:这道题还是有点似懂非懂.....
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 8 #define maxn 205 9 10 int n,t,st,en; 11 struct Mat 12 { 13 int mat[maxn][maxn]; 14 void init() 15 { 16 memset(mat,-1,sizeof(mat)); 17 } 18 }; 19 20 int v[1005];//离散化用 21 Mat ans,tmp,map; 22 int cnt;//顶点个数 23 void init() 24 { 25 int val,s,e; 26 memset(v,0,sizeof(v)); 27 cnt=0; 28 ans.init(); 29 tmp.init(); 30 map.init(); 31 for(int i=0;i<maxn;i++) 32 ans.mat[i][i]=0; 33 for(int i=0;i<t;i++) 34 { 35 scanf("%d%d%d",&val,&s,&e); 36 if(v[s]==0) 37 { 38 ++cnt; 39 v[s]=cnt; 40 } 41 if(v[e]==0) 42 { 43 ++cnt; 44 v[e]=cnt; 45 } 46 if(map.mat[v[s]][v[e]]<0 || map.mat[v[s]][v[e]] > val) 47 map.mat[v[s]][v[e]]=map.mat[v[e]][v[s]]=val; 48 } 49 } 50 51 void floyd(Mat b,Mat c) 52 { 53 tmp.init(); 54 for(int k=1;k<=cnt;k++) 55 for(int i=1;i<=cnt;i++) 56 for(int j=1;j<=cnt;j++) 57 { 58 if(b.mat[i][k] <0 || c.mat[k][j] <0)//意味着是inf 59 continue; 60 if(tmp.mat[i][j]<0 || tmp.mat[i][j] > b.mat[i][k] + c.mat[k][j] ) 61 tmp.mat[i][j] = b.mat[i][k] + c.mat[k][j]; 62 } 63 } 64 65 Mat copy() 66 { 67 Mat a; 68 for(int i=0;i<=cnt;i++) 69 for(int j=0;j<=cnt;j++) 70 a.mat[i][j]=tmp.mat[i][j]; 71 return a; 72 } 73 74 void solve() 75 { 76 while(n)//虽然这里是n,像是更新了n次。但是下面80行那里第一次调用的时候其实并未更新。只是把map,传递给tmp再转给ans. 77 { 78 if(n&1) 79 { 80 floyd(ans,map); 81 ans=copy(); 82 } 83 floyd(map,map); 84 map=copy(); 85 n>>=1; 86 } 87 } 88 89 int main() 90 { 91 while(scanf("%d%d%d%d",&n,&t,&st,&en) != EOF) 92 { 93 init(); 94 solve(); 95 printf("%d\n",ans.mat[v[st]][v[en]]); 96 } 97 return 0; 98 }