您的位置:首页 > 其它

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

2012-08-21 20:18 369 查看
http://poj.org/problem?id=3613



题意:

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

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

题解:

我们知道线性代数中有:在只 含有 01邻接矩阵 A的K次 方C=A^K,C[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 == 0) return 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];

if(len < a.m[x1][y1])
{

a.m[x1][y1] = a.m[y1][x1] = len ;

}

}

int j;

a = solve(a,n - 1);// n 条边 ,经过 n-1 个点

/*for(i = 0; i < num;i++)
{
for(j = 0; j < num;j++)
{
printf("%d ",a.m[i][j]);
}

printf("\n");

}*/

printf("%d\n",a.m[map1[s]][map1[e]]) ;

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: