POJ 3613 Cow Relays floyd+快速幂

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>

using namespace std;

int N,T,S,E,num;
map<int,int> mp;

struct Matrix{
    int ma[210][210];
    void clear(){
        memset(ma,0x3f,sizeof(ma)); //初始化一定要大,否则WA
    }
};

Matrix Floyd(Matrix a,Matrix b){
    Matrix dis;
    dis.clear();
    int i,j,k;
    for(k=1;k<=num;k++) //一次floyd  是找到一个中间点
        for(i=1;i<=num;i++)
            for(j=1;j<=num;j++)
                if(dis.ma[i][j]>a.ma[i][k]+b.ma[k][j])
                    dis.ma[i][j]=a.ma[i][k]+b.ma[k][j];
    return dis;
}

Matrix Solve(Matrix a,int k){
    Matrix ans=a;
    while(k){
        if(k&1){
            ans=Floyd(ans,a);
        }
        a=Floyd(a,a);
        k>>=1;
    }
    return ans;
}

int main(){

    //freopen("input.txt","r",stdin);

    Matrix a;
    while(~scanf("%d%d%d%d",&N,&T,&S,&E)){
        num=0;
        mp.clear();
        a.clear();
        int u,v,w;
        while(T--){
            scanf("%d%d%d",&w,&u,&v);
            if(mp[u]==0)
                mp[u]=++num;
            if(mp[v]==0)
                mp[v]=++num;
            if(a.ma[mp[u]][mp[v]]>w)
                a.ma[mp[u]][mp[v]]=a.ma[mp[v]][mp[u]]=w;
        }   
        a=Solve(a,N-1);     // N 条边  ,经过 N-1 个点 
        printf("%d\n",a.ma[mp[S]][mp[E]]);
    }
    return 0;
}
我们知道线性代数中有: 在只 含有 01邻接矩阵  AK次 方 C=A^KC[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 条边的  松驰一次 ;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值