POJ3613 k边最短路

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

Floyd求最短路的实质是矩阵的自乘。( i , k )是第 i 行第k列,( k , j )是第k行第 j 列;用它们的max更新( i , j ),正是矩阵的自乘。

给一个矩阵赋予“已走 r 条边”的意义,则已走m条边的矩阵×已走n条边的矩阵得到的是已走m+n条边的矩阵。

用快速幂一样的方法加速,就行了。

重载运算符有待练习。

注意要先ans=a,n - -,原因见注释。

PS:(2018.6.14)因为每次把tmp赋值成INF,所以原来的 i , j 连通性消失,就得到精确的走n-1条边的答案了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=205;
int n,m,s,t,map[1005],cnt;
struct Jz{
    ll c[N][N];
    Jz operator * (const Jz &a) const
    {
        Jz tmp;
        memset(tmp.c,1,sizeof tmp.c);
        for(int k=1;k<=cnt;k++)
            for(int i=1;i<=cnt;i++)
                for(int j=1;j<=cnt;j++)
                    tmp.c[i][j]=min(tmp.c[i][j],c[i][k]+a.c[k][j]);
//                    printf("k=%d i=%d j=%d c=%lld
",k,i,j,c[i][k]);//
        return tmp;
    }
}ans,a;
int main()
{
    memset(a.c,1,sizeof a.c);
    scanf("%d%d%d%d",&n,&m,&s,&t);
    int x,y;ll z;
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%d%d",&z,&x,&y);
//        printf("(%lld)",z);
        if(!map[x])map[x]=++cnt;
        if(!map[y])map[y]=++cnt;
        a.c[map[x]][map[y]]=a.c[map[y]][map[x]]=min(a.c[map[x]][map[y]],z);
//        printf("(%d %d %lld %lld)",map[x],map[y],a.c[map[x]][map[y]],ans.c[map[x]][map[y]]);
    }
//    printf("[%d %d %d %d]
",map[4],map[6],map[8],map[9]);
//    printf("(%lld)",a.c[map[s]][map[t]]);
    ans=a;n--;///////不然i,j的值就改成min(k,j)了! 
    for(;n;n>>=1)
    {
        if(n&1)ans=ans*a;
        a=a*a;
    }
    printf("%lld",ans.c[map[s]][map[t]]);
    return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/8799282.html