[洛谷P1613 跑路]最短路+倍增思想+DP
碎碎念:
哈哈,数学建模寄了,四级做了套卷子感觉能过,开摆
这几天狂肝别的作业+数据结构把c语言大作业出成开学小作业,我真的栓Q……
开肝ACM
题意
给n个点,m条有向边,每条边的长度均为1。每次花费1的时间可以跑\(2^k\)的长度,k为任意自然数,问从点1跑到点n的最短路。
数据范围
\(n<=50,m<=10000,最优长度<=maxlongint\)
分析
显然,假如x到y有长度为\(2^{i-1}\)的路径,可以用1的时间到达,y到z有长度为\(2^{i-1}\)的路径,可以用1的时间到达,那么x到z有长度为\(2^i\)的路径,可以用1的时间到达。
\(f[i][j][k]\)表示i和j之间是否有长度为\(2^k\)的边,\(n<=50\),floyd+倍增+DP。先把所有可用1时间到达的两个点间连边,再floyd求解。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
int n,m;
int f[60][60][128],d[60][60];
void solve()
{
cin>>n>>m;
memset(d,0x3f,sizeof d);
for(int i=1;i<=m;i++)
{
int a,b;cin>>a>>b;
f[a][b][0]=1;
d[a][b]=1;
}
for(int x=1;x<=63;x++)
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(f[i][k][x-1]==1&&f[k][j][x-1]==1)
f[i][j][x]=1,d[i][j]=1;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
cout<<d[1][n];
}
main()
{
solve();
}