P1613 跑路 题解

思维题。

我们考虑用倍增。

\(f[i][j][k]\) 表示从 \(i\)\(j\) 有一条长度为 \(2^k\) 的路径。

转移方程为:

假设有三个点 \(i, j, k\)

如果 \(f[i][j][M - 1] = 1\)\(f[j][k][M - 1] = 1\), 则 \(f[i][k][M] = 1\)

倍增的常见思路。

如果两个点直接能有一条 \(2^k\) 的路径,就在两点直接建一条边。

然后跑个最短路就行了。

/*
	Work by: TLE_Automation
*/
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define int long long
using namespace std;

const int N = 1e6 + 10;
const int MAXN = 2e5 + 10;

inline char readchar() {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline int read() {
#define readchar getchar
	int res = 0, f = 0;char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch); ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}

inline void print(int x) {
	if (x < 0 ) putchar('-'), x = -x;
	if (x > 9 ) print(x / 10);
	putchar(x % 10 + '0');
}

int cnt = 0, head[MAXN];
int f[52][52][70], dis[100][100];
int n, m;


signed main() {
	n = read(), m = read();
	memset(dis, 0x3f, sizeof dis);
	for(int i = 1, u, v; i <= m; i++) {
		u = read(), v = read();
		dis[u][v] = 1, f[u][v][0] = 1;
	}
	for(int M = 1; M <= 64; M++) {
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= n; j++) {
				for(int k = 1; k <= n; k++) {
					if(f[i][j][M - 1] != 0 && f[j][k][M - 1] != 0) f[i][k][M] = 1, dis[i][k] = 1;
				}
			}
		}
	}
	for(int k = 1; k <= n; k++) {
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= n; j++) {
				dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
			}	
		}
	}
	cout << dis[1][n];
}
posted @ 2022-05-25 22:12  TLE_Automation  阅读(47)  评论(0)    收藏  举报