洛谷P1613 跑路

\(\Large\textbf{Description: } \large{有一个n个点m条边的有向图,边权为1千米。有一个跑路器,每秒种可以跑2^{k}次方千米,求1到n的最短时间。(n \leq 50, m \leq 10000)}\)

\(\Large\textbf{Solution: } \large{容易想到倍增,可是我一开始没有想出来怎么做。看了题解后才明白。\\回忆倍增求lca的时候,2^k可以由2^{k - 1}转移得到,所以设bool型变量\text{dis[i][j][k]}表示\\i到j是否有一条长度为2^{k}的路径,那么容易得到\text{dis[i][j][k] = dis[i][p][k-1] && dis[p][j][k-1]}。\\然后如果i与j之间有一个k成立,那么边权为1,直接跑\text{Floyd}就行了。}\)

\(\Large\textbf{Code: }\)

#include <bits/stdc++.h>
#define gc() getchar()
#define LL long long
using namespace std;
const int N = 55;
const int inf = 0x7fffffff;
int n, m, g[N][N], dis[N][N][65];

inline int read() {
	char ch = gc();
	int ans = 0, flag = 1;
	while (!isdigit(ch)) ch = gc(); 
	while (isdigit(ch)) ans = ans * 10 + ch - '0', ch = gc();
	return ans * flag;	
}

int main() {
	n = read(), m = read();
	int x, y;
	for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) g[i][j] = 20;
	while (m--) x = read(), y = read(), g[x][y] = 1, dis[x][y][0] = 1;
	for (int i = 1; i <= 64; ++i)
		for (int j = 1; j <= n; ++j)
			for (int k = 1; k <= n; ++k)
				for (int p = 1; p <= n; ++p)
					if (dis[j][k][i - 1] && dis[k][p][i - 1]) dis[j][p][i] = 1, g[j][p] = 1;
	for (int k = 1; k <= n; ++k)
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= n; ++j)
				g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
	cout << g[1][n] << endl;
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Miraclys/p/12559972.html
今日推荐