题目大意:
有
n
n
n个点,每个点之间的边权是一个周期。
求从
1
1
1出发经过
m
m
m条边到
n
n
n的最小权值
解题思路:
S
o
l
u
t
i
o
n
1
Solution\ 1
Solution 1
d
p
dp
dp
设
f
i
,
j
f_{i,j}
fi,j表示第
i
i
i天到达第
j
j
j个点的最少花费
则得出转移方程:
f
i
,
j
=
m
i
n
(
f
i
,
j
,
f
i
−
1
,
k
+
a
k
,
j
,
(
a
i
,
j
,
0
−
1
)
m
o
d
k
+
1
)
f_{i,j} = min(f_{i,j},\ f_{i-1,k}+a_{k,j,(a_{i,j,0}-1)\ mod\ k + 1)}
fi,j=min(fi,j, fi−1,k+ak,j,(ai,j,0−1) mod k+1)
a
i
,
j
,
0
a_{i,j,0}
ai,j,0表示周期长度
a
i
,
j
,
k
a_{i,j,k}
ai,j,k表示从点
i
i
i到点
j
j
j在周期中第
k
k
k天的花费,若
a
i
,
j
,
k
=
0
a_{i,j,k} =0
ai,j,k=0,则周期中的第
k
k
k天不能走
S
o
l
u
t
i
o
n
2
Solution\ 2
Solution 2
分层图SPFA
这里不再赘述
A c c e p t e d c o d e : Accepted\ code: Accepted code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define rr register
using namespace std;
const int inf = 1e9;
int n, m;
int a[101][101][21], f[201][101];
inline signed read() {
int f = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) f = f * 10 + c - 48, c = getchar();
return f;
}
void write(int x) {
if (x > 9) write(x/10); putchar(x%10+48); return;
}
signed main() {
/*freopen("lines.in", "r", stdin);
freopen("lines.out", "w", stdout);*/
n = read(); m = read();
for (rr int i = 1; i <= n; ++i) {
for (rr int j = 1; j <= n; ++j)
if (i != j) {
a[i][j][0] = read();
for (rr int T = 1; T <= a[i][j][0]; ++T)
a[i][j][T] = read(),
a[i][j][T] = a[i][j][T] == 0 ? inf : a[i][j][T];
}
}
for (rr int i = 0; i <= m; ++i)
for (rr int j = 0; j <= n; ++j)
f[i][j] = inf;
f[0][1] = 0;
for (rr int k = 1; k <= m; ++k)
for (rr int i = 1; i <= n; ++i)
for (rr int j = 1; j <= n; ++j)
if (i != j)
f[k][j] = min(f[k][j], f[k-1][i] + a[i][j][(k-1)%a[i][j][0]+1]);
write(f[m][n] == inf ? 0 : f[m][n]);
return 0;
}