题目链接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
",dis[que[S]][que[E]]);
}