题目大意:给定一张无向图,求从s出发恰好经过n条边到达e的最短路
倍增Floyd……为何大家都管这个叫做矩阵乘法- - 算了为何要纠结这种事- -
令f[p][i][j]表示走2^p步从i到达j的最短路 有f[p][i][j]=min{f[p-1][i][k]+f[p-1][k][j]}
将n进行二进制拆分 用矩阵g记录答案矩阵 对于每一位p 用f[p]和g两个矩阵搞出h 再将h的值赋给g
切忌直接用f[p]更新g 这样可能导致g的上一次的值被继承到下一次里 这样相当于这一步没跑
100条边,因此最多200个点,离散化一下就行了
这编号真是反人类- -
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 220 using namespace std; struct abcd{ int x,y,z; }edges[110]; int n,t,s,e,tot; int f[M][M],g[M][M],h[M][M]; pair<int,int*> b[M<<1]; void Initialize() { memset(f,0x3f,sizeof f); memset(h,0x3f,sizeof h); for(int i=1;i<=tot;i++) h[i][i]=0; } int main() { int temp,i,j,k; cin>>n>>t>>s>>e; for(i=1;i<=t;i++) { scanf("%d%d%d",&edges[i].z,&edges[i].x,&edges[i].y); b[i+i-1]=make_pair(edges[i].x,&edges[i].x); b[i<<1]=make_pair(edges[i].y,&edges[i].y); } b[i+i-1]=make_pair(s,&s); b[i<<1]=make_pair(e,&e); sort(b+1,b+t+t+3); for(i=1;i<=t+1<<1;i++) { if(i==1||b[i].first!=b[i-1].first) ++tot; *b[i].second=tot; } Initialize(); for(i=1;i<=t;i++) f[edges[i].x][edges[i].y]=f[edges[i].y][edges[i].x]=edges[i].z; for(temp=0;(1<<temp)<=n;temp++) { if( n&(1<<temp) ) { memset(g,0x3f,sizeof g); for(k=1;k<=tot;k++) for(i=1;i<=tot;i++) for(j=1;j<=tot;j++) g[i][j]=min(g[i][j],f[i][k]+h[k][j]); memcpy(h,g,sizeof h); } memset(g,0x3f,sizeof g); for(k=1;k<=tot;k++) for(i=1;i<=tot;i++) for(j=1;j<=tot;j++) g[i][j]=min(g[i][j],f[i][k]+f[k][j]); memcpy(f,g,sizeof f); } cout<<h[s][e]<<endl; return 0; }
时间: 2024-10-13 12:05:26