经过N条边的最短路

http://acm.pku.edu.cn/JudgeOnline/problem?id=3613

求经过N条边的最短路 (2 ≤ N ≤ 1,000,000)

 

倍增floyd,主体是矩阵乘法。考虑一个x边的路径矩阵和y边的路径矩阵,两个矩阵用类似floyd的方法结合起来,就得到x+y边的路径矩阵,现在想要得到N边路径矩阵

然后就是“快速幂”的思想啦...把N拆成2的幂,只需要log(N)次矩阵乘法就搞定

伪floyd O(N^3),所以总的时间复杂度O(logN*n^3) 其中n是点的个数 由于最多100个边,所以n最大200

虽说只有最多200个点,然而点点序号却很迷的到了1000,所以用了离散化,把点的序号映射到1~200范围

答案矩阵开始时候应该为单位矩阵 在这个倍增floyd定义下 单位矩阵应该是迹为0 其他值为正无穷

#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
const int maxn = 207, INF = 0x3f3f3f3f;
map<int, int>M;
int cnt, n, t, s, e;
struct floyd{
    int a[maxn][maxn];
    floyd(){
        memset(a, INF, sizeof(a));
    }
    floyd operator * (const floyd& b){
        floyd c;
        for(int i = 1; i <= cnt; i++)
            for(int j = 1; j <= cnt; j++)
                for(int k = 1; k <= cnt; k++)
                    if(c.a[i][j] > a[i][k] + b.a[k][j])
                        c.a[i][j] = a[i][k] + b.a[k][j];
        return c;
    }
}st, ans;
void quick(){
   // ans = st;
   // n--;
    while(n){
        if(n&1){
            ans = ans*st;
        }
        st = st * st;
        n >>= 1;
    }
}
int main(){
    scanf("%d%d%d%d", &n, &t, &s, &e);
    cnt = 0;
    while(t--){
        int w, x, y;
        scanf("%d%d%d", &w, &x, &y);
        if(M[x])
            x = M[x];
        else
            x = M[x] = ++cnt;
        if(M[y])
            y = M[y];
        else
            y = M[y] = ++cnt;
        st.a[x][y] = st.a[y][x] = w;
    }
    for(int i = 1; i <= cnt; i++)
        ans.a[i][i] = 0;
    quick();
    printf("%d", ans.a[M[s]][M[e]]);
    return 0;
}

 

posted @ 2017-09-08 23:34  DearDongchen  阅读(639)  评论(0编辑  收藏  举报