POJ 3613
題意:在無向圖中有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)
#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; }
思路:此題正解應該是矩陣乘法,但是重定義了,區別于線性代數里面的乘法(其實可以看出無論哪種定義,只要能推出矩陣在該定義下滿足交換律即可,因為可以用快速冪來加速)。設原圖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; }
轉載于:https://www.cnblogs.com/wangzhili/p/3950235.html
總結
- 上一篇: CentOS6部署phpmyadmin;
- 下一篇: windows 开启防火墙策略允许ftp