POJ3613 Cow Relays 矩阵快速幂

题目链接https://www.luogu.com.cn/problem/P2886

分析

这道题,的确是个一眼题。。。。
除了离散化不想说什么。
最开始的时候发现这题的输入很坑,它给的点的编号不是连续的,也就是说虽然最多只有100个点但点的编号可能会很大,那就只能离散化了,最开始用的去重+二分,调了半天不对,发现这很麻烦,于是换了一种,点的编号没什么用,除了当一个标记之外,不需要维护相对大小,所以直接用一个数字代替就好,后来发现最开始的离散化求去重后数组长度写错了。。。
至于这道题怎么做,我真的懒得说了。请参考一个月前写的东西:
NOI ONLINE魔法
如果没什么思路,这里还有个ppt。(感觉如果很久前我分享的时候听的认真的同志应该都能做出来。。)
PPT
算了,我还是良心点写几句吧。
这道题的朴素做法是什么?外层循环\(1~n\),对整张图松弛\(n\)次,这个应该比较好理解,但对于这道题来说行不通,因为\(n\)真的太大了,肯定会T,所以要用一个更珂学的手段,矩阵快速幂。
对于一个矩阵\(A\)\(A^k\)就表示它在当前定义下的第\(k\)次状态,放到这道题来说就是经过\(k\)条路之后的最短路,直接乘\(k\)次还是会T,用快速幂加一下速就行,这样乘的时间复杂度就会很小,因为最多只乘32次,这道题可能还到不了。
还有,终点\(e\)这个变量千万不要写小写的,因为边也是用\(e\)存的,用\(edge\)的自行忽略,我因为这个CE了半天
n--又是怎么回事呢?不memcpy的话就不用,因为我cpy过去就已经是走一条边的最短路了,不cpy的话就是零条边

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e2+10;
int t,dis[N][N],f[N][N];
struct Edge{
    int to,fro,val;
}e[N<<1];
int tt,que[N*N*N];
void Mul(int a[N][N],int b[N][N],int c[N][N]){
    int tep[N][N];
    memset(tep,0x3f,sizeof(tep));
    for(int i=1;i<=tt;i++)
    for(int j=1;j<=tt;j++)
    for(int k=1;k<=tt;k++)
        tep[i][j]=min(tep[i][j],b[i][k]+c[k][j]);
    memcpy(a,tep,sizeof(tep));
}
int main(){
    memset(f,0x3f,sizeof(f));
    int n,S,E;
    scanf("%d%d%d%d",&n,&t,&S,&E);
    for(int i=1;i<=t;i++){
        int a,b,c;
        scanf("%d%d%d",&c,&a,&b);
        if(!que[a])que[a]=++tt;
        if(!que[b])que[b]=++tt;
        f[que[a]][que[b]]=f[que[b]][que[a]]=min(f[que[a]][que[b]],c);
    }
    memcpy(dis,f,sizeof(f));
    n--;
    while(n){
        if(n&1){
            Mul(dis,f,dis);
        }
        Mul(f,f,f);
        n>>=1;
    }
    printf("%d\n",dis[que[S]][que[E]]);
}
posted @ 2020-04-26 23:23  An_Fly  阅读(93)  评论(0编辑  收藏  举报