题目地址:
https://www.luogu.com.cn/problem/P1613
题目描述:
小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在
6
:
00
6:00
6:00之前到达公司,否则这个月工资清零。可是小A偏偏又有赖床的坏毛病。于是为了保住自己的工资,小A买了一个空间跑路器,每秒钟可以跑
2
k
2^k
2k千米(
k
k
k是任意自然数)。当然,这个机器是用longint
存的,所以总跑路长度不能超过maxlongint
千米。小A的家到公司的路可以看做一个有向图,小A家为点
1
1
1,公司为点
n
n
n,每条边长度均为一千米。小A想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到公司。数据保证
1
1
1到
n
n
n至少有一条路径。
输入格式:
第一行两个整数
n
,
m
n,m
n,m,表示点的个数和边的个数。
接下来
m
m
m行每行两个数字
u
,
v
u,v
u,v,表示一条
u
u
u到
v
v
v的边。
输出格式:
一行一个数字,表示到公司的最少秒数。
数据范围:
50
%
50\%
50%的数据满足最优解路径长度
≤
1000
\leq 1000
≤1000;
100
%
100\%
100%的数据满足
2
≤
n
≤
50
2\leq n \leq 50
2≤n≤50,
m
≤
1
0
4
m \leq 10 ^ 4
m≤104,最优解路径长度
≤
\leq
≤maxlongint
。
设 f [ u ] [ v ] [ k ] f[u][v][k] f[u][v][k]表示从 u u u走 2 k 2^k 2k的距离能否到达 v v v。因为所有边的长度都是 1 1 1,所以如果存在 u → v u\to v u→v,则 f [ u ] [ v ] [ 0 ] = 1 f[u][v][0]=1 f[u][v][0]=1,有递推关系 f [ u ] [ v ] [ k ] = f [ u ] [ s ] [ k − 1 ] ∧ f [ s ] [ v ] [ k − 1 ] f[u][v][k]=f[u][s][k-1]\land f[s][v][k-1] f[u][v][k]=f[u][s][k−1]∧f[s][v][k−1]而如果 ∃ k ≥ 0 , f [ u ] [ v ] [ k ] = 1 \exists k\ge 0,f[u][v][k]=1 ∃k≥0,f[u][v][k]=1,则从 u u u到 v v v的时间就是 1 1 1;否则 u u u到 v v v不直接可达(需要用多次跑路器)。构建新图,该图里的两个点如果一次跑路器能到,则连长度为 1 1 1的边。在新图上求 1 1 1到 n n n的最短路即可,可以用Dijkstra来做。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 60, K = 65;
int n, m;
int g[N][N], dist[N];
bool vis[N];
bool f[N][N][K];
int dijkstra() {
memset(dist, 0x3f, sizeof dist);
memset(vis, 0, sizeof vis);
dist[1] = 0;
for (int i = 1; i <= n; i++) {
int t = -1;
for (int j = 1; j <= n; j++)
if (!vis[j] && (t == -1 || dist[j] < dist[t])) t = j;
if (t == n) break;
vis[t] = true;
for (int j = 1; j <= n; j++)
if (!vis[j]) dist[j] = min(dist[j], dist[t] + g[t][j]);
}
return dist[n];
}
int main() {
memset(g, 0x3f, sizeof g);
scanf("%d%d", &n, &m);
while (m--) {
int a, b;
scanf("%d%d", &a, &b);
f[a][b][0] = true;
g[a][b] = 1;
}
for (int i = 1; i <= n; i++) g[i][i] = 0;
for (int l = 1; l < K; l++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
if (f[i][k][l - 1] && f[k][j][l - 1]) {
f[i][j][l] = true;
if (i != j) g[i][j] = 1;
}
printf("%d\n", dijkstra());
}
时间复杂度 O ( n 3 ) O(n^3) O(n3),空间 O ( n 2 ) O(n^2) O(n2)。