BZOJ1706奶牛接力跑

这个东西思路还是不错的。

解法就是把矩阵幂的加法改成取min,乘法改成加法就好,和floyed是一样的。这样的话,矩阵操作一次就相当于松弛了一次最短路。

建矩阵的过程也比较简单,可以离散化,当然下面有另一种更优秀的打法,可以借鉴一下。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
using namespace std;
int read(){
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){
        if(x=='-') f=-1;
        x=getchar();
    }while(x>='0'&&x<='9'){
        sum=sum*10+x-'0';
        x=getchar();
    }return sum*f;
}
int k,m,s,e,num;
int id[2000];
struct Matrix{
    int x[600][600];
    void add(int a,int b,int c){
        x[a][b]=c;
        return ;
    }
    friend Matrix operator * (Matrix a,Matrix b){
        Matrix c;
        memset(c.x,0x3f,sizeof(c.x));
        for(int i=1;i<=num;i++)
            for(int j=1;j<=num;j++)
                for(int k=1;k<=num;k++)
                    c.x[i][j]=min(c.x[i][j],a.x[i][k]+b.x[k][j]);
        return c;
    }
    void db(){
        cout<<endl;
        for(int i=1;i<=num;i++){
            for(int j=1;j<=num;j++)
                cout<<x[i][j]<<" ";
            cout<<endl;
        }
    }
    void put(int a,int b){
        printf("%d",x[a][b]);
        return ;
    }
}a;
void qpow(int k){
    Matrix c=a,b=a;
//    b.db();
    for(;k;k>>=1,b=b*b)
        if(k&1) c=c*b;
//    c.db();
    a=c;
}
int main(){
    k=read();m=read();s=read();e=read();
    memset(a.x,0x3f,sizeof(a.x));
    for(int i=1,x,y,z;i<=m;i++){
        z=read();x=read();y=read();
        id[x]=id[x]?id[x]:++num;
        id[y]=id[y]?id[y]:++num;
        a.add(id[x],id[y],z);
        a.add(id[y],id[x],z);
    }
//    a.db();
    qpow(k-1);
//    a.db();
    a.put(id[s],id[e]);
    return 0;
}
View Code

这种打法是直接用a做的初始矩阵,根据An=A*An-1做的操作,因为一开始不太清楚单位矩阵是谁。

后来想通了,以前的单位矩阵之所以是那样的,是因为单位矩阵的定义是另一个矩阵该矩阵还是原矩阵,以前的之所以是对角线全是1,是因为通过矩阵乘后这个矩阵可以满足单位矩阵性质。

那么这个题的单位矩阵是正无穷矩阵,因为该任何一个矩阵乘完该矩阵还是原矩阵(因为取min嘛)。

转载于:https://www.cnblogs.com/Yu-shi/p/11203002.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值