[洛谷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();
}

posted @ 2022-09-07 09:18  Hssliu  阅读(20)  评论(0)    收藏  举报