POJ 3613
2014-04-30 18:39
369 查看
题意:在无向图中有n条边,现在给出你一个起点S和一个终点E,让你求从S到E经过且仅K条边的最短路径。注意此题中K远大于n,如果K小于n的话直接一边广搜就过了,第一次没注意到这个条件敲了一个BFS,结果WA了。
思路:此题正解应该是矩阵乘法,但是重定义了,区别于线性代数里面的乘法(其实可以看出无论哪种定义,只要能推出矩阵在该定义下满足交换律即可,因为可以用快速幂来加速)。设原图G对应的邻接矩阵为M,则M的k次幂中M[i][j]就表示从i点到j点经过k条边路径的个数!那么只需要重新定义一下矩阵乘法:M[i][j]表示从i点到j点的的最短路径长度,即M[i][j] = min(M[i][j],M[i][k]+M[k][j])(这个就是floyd算法的核心,DP思想),可以证明该定义满足交换律,因此可以用快速幂,考虑M^2,它表示从i到j经过2条边的最短路径,同理推出M^n表示从i到j经过n条边的最短路径,因此本题得解。关于矩阵乘法的应用是参考2008年国家集训队论文《矩阵乘法在信息学中的应用》(俞华程)中看到的,网上此题解法大都参考该论文,在网上看了别人解释的没怎么看懂,直接看论文去了,发现论文里面讲的很明白也很透彻,但是经过别人转述意思可能就不一样了,其实我也说的不怎么清楚,所以建议直接去看论文。
网盘下载地址:http://yunpan.cn/QNeFIw2wIef4B (访问密码:7b0c)
思路:此题正解应该是矩阵乘法,但是重定义了,区别于线性代数里面的乘法(其实可以看出无论哪种定义,只要能推出矩阵在该定义下满足交换律即可,因为可以用快速幂来加速)。设原图G对应的邻接矩阵为M,则M的k次幂中M[i][j]就表示从i点到j点经过k条边路径的个数!那么只需要重新定义一下矩阵乘法:M[i][j]表示从i点到j点的的最短路径长度,即M[i][j] = min(M[i][j],M[i][k]+M[k][j])(这个就是floyd算法的核心,DP思想),可以证明该定义满足交换律,因此可以用快速幂,考虑M^2,它表示从i到j经过2条边的最短路径,同理推出M^n表示从i到j经过n条边的最短路径,因此本题得解。关于矩阵乘法的应用是参考2008年国家集训队论文《矩阵乘法在信息学中的应用》(俞华程)中看到的,网上此题解法大都参考该论文,在网上看了别人解释的没怎么看懂,直接看论文去了,发现论文里面讲的很明白也很透彻,但是经过别人转述意思可能就不一样了,其实我也说的不怎么清楚,所以建议直接去看论文。
网盘下载地址:http://yunpan.cn/QNeFIw2wIef4B (访问密码:7b0c)
#include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 111 using namespace std; class Matrix{ public: int m[MAXN][MAXN]; Matrix(){ memset(m, -1, sizeof(m)); } }; int N = 0; Matrix mtMul(Matrix A, Matrix B){ Matrix tmp; for(int i = 0;i < N;i ++) for(int j = 0;j < N;j ++) for(int k = 0;k < N;k ++){ if(A.m[i][k] == -1 || B.m[k][j] == -1) continue; int temp = A.m[i][k] + B.m[k][j]; if(tmp.m[i][j] == -1 || tmp.m[i][j] > temp) tmp.m[i][j] = temp; } return tmp; } Matrix mtPow(Matrix A, int k){ if(k == 1) return A; Matrix tmp = mtPow(A, k >> 1); Matrix res = mtMul(tmp, tmp); if(k & 1) res = mtMul(res, A); return res; } int main(){ int cnt[1111]; int n, t, s, e; int u, v, w; /* freopen("in.c", "r", stdin); */ while(~scanf("%d%d%d%d", &n, &t, &s, &e)){ N = 0; Matrix G; memset(cnt, -1, sizeof(cnt)); for(int i = 0;i < t;i ++){ scanf("%d%d%d", &w, &u, &v); if(cnt[u] == -1) cnt[u] = N++; if(cnt[v] == -1) cnt[v] = N++; G.m[cnt[u]][cnt[v]] = w; G.m[cnt[v]][cnt[u]] = w; } Matrix tmp = mtPow(G, n); printf("%d\n",tmp.m[cnt[s]][cnt[e]]); } return 0; }