poj 3613 Cow Relays (矩阵乘法的变形 floyd 倍增法)

http://poj.org/problem?id=3613


题意:

求从一个点s 到 一点 e 经过 n 条边的最短路经是多少(可以有重边):

看到很难多解题报告说的是n 个点 ,其实,n 条边 应该是 n - 1 个点

题解:

我们知道线性代数中有:在只 含有 01邻接矩阵 AK次 方C=A^KC[i][j]表示i点到j点正好经过K条边的路径数。
而floyd则是每次使用一个中间点k去更新i,j之间的距离,那么更新成功表示i,j之间恰有一个点k时的最短路,如果做N - 1次floyd那么不就是i,j之间借助N - 1 个点时的最短路了

当 c[i][j] > a[i][k] + a[k][j]  则更新

第二次将c[i][j]拷贝回到a[i][j]当中,并将c[i][j]重新置为INF,再做一次,则是在原来的基础上在i,j之间再用一个点k来松弛,这时候i,j之间实际上已经是两个点了,

但是这个题的   n (边数太大)我们要用到 倍增法,其实即使 二分思想  例如  经过 5  条边 把  (4 个点)  ==  两个 2 条边的  松驰一次 ;


  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include<string>
 11 #define Min(a,b) a<b?a:b
 12 #define Max(a,b) a>b?a:b
 13 #define CL(a,num) memset(a,num,sizeof(a));
 14 #define maxn  40
 15 #define eps  1e-6
 16 #define inf 100000000
 17 #define mx 1<<60
 18 #define ll   __int64
 19 using namespace std;
 20 map<int ,int>map1;
 21 int num ;
 22 struct matrix
 23 {
 24     int m[210][210];
 25     void clear()
 26     {
 27         memset(m,0x3f,sizeof(m));//错在这好几次 ,貌似这道题的 数很大 我的 inf  开的不够大
 28        /*for(int i = 0; i < 210 ;i++)
 29        {
 30            for(int  j = 0 ; j < 210 ;j++)
 31                m[i][j] = inf;
 32        }*/
 33     }
 34 };
 35 
 36  matrix floyd(matrix a,matrix b)
 37 {
 38 
 39     matrix dis;
 40     dis.clear();
 41     int i,j,k;
 42     for(k = 0; k < num;k++)//一次floyd  是找到一个中间点
 43     for(i = 0 ; i < num;i++ )
 44     {
 45         for(j = 0;j < num;j++)
 46         {
 47 
 48             if(dis.m[i][j] > a.m[i][k] + b.m[k][j])
 49             {
 50                  dis.m[i][j] = a.m[i][k] + b.m[k][j] ;
 51                  //printf("%d %d %d  ++++\n",dis.m[i][j],i , j);
 52 
 53 
 54             }
 55 
 56         }
 57     }
 58 
 59     return dis;
 60 }
 61 matrix  solve(matrix a,int k)
 62 {
 63     if(k == 0return  a;
 64     matrix ans ;
 65 
 66     ans = a ;
 67 
 68     while(k)
 69     {
 70 
 71         if(k&1)
 72         {
 73             ans = floyd(ans,a);
 74 
 75         }
 76         a = floyd(a,a);
 77 
 78 
 79         k>>=1;
 80     }
 81     return ans ;
 82 }
 83 int main()
 84 {
 85     int t,n,m,s,e,x,y,len,i;
 86     matrix a;
 87     while(scanf("%d%d%d%d",&n,&t,&s,&e)!=EOF)
 88     {
 89          num = 0;
 90          map1.clear() ;
 91          a.clear() ;
 92 
 93         for(i = 0; i < t;i++)
 94         {
 95             scanf("%d %d %d",&len,&x,&y);
 96             if(map1.find(x)==map1.end()) map1[x] = num ++;
 97             if(map1.find(y)==map1.end()) map1[y] = num ++;
 98             int x1 = map1[x];
 99             int y1 = map1[y];
100 
101             if(len < a.m[x1][y1])
102             {
103 
104                 a.m[x1][y1] = a.m[y1][x1] = len ;
105 
106 
107             }
108 
109 
110         }
111 
112          int  j;
113 
114 
115           a = solve(a,n - 1);// n 条边  ,经过 n-1 个点
116 
117           /*for(i = 0; i < num;i++)
118          {
119              for(j = 0; j < num;j++)
120           {
121               printf("%d ",a.m[i][j]);
122           }
123 
124              printf("\n");
125 
126          }*/
127 
128         printf("%d\n",a.m[map1[s]][map1[e]]) ;
129 
130     }
131 }
  
原文地址:https://www.cnblogs.com/acSzz/p/2649657.html