类似floyd的动态规划 + 二分求幂
裸DP的复杂度太高,写法如下:
F(l, i) = max( f(l-1, j) +v[j][i] )
时间复杂度为:O(n^2*L),L太大,无法接受
先预处理2^p + 1长度的值,利用了二进制的思想,然后用上面DP的思想拼接。
f[p][a][b] = 长度为2^p + 1, 第一个是a, 最后一个是b的最大value.
然后拼接~,复杂度O(n^3*logL)
注意:有L个时间点,那么就有L-1个时间段
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 102
#define inf 0x3f3f3f3f3f3f
typedef long long LL;
int n, l;
LL f[20][N][N], dp[2][N];
int main() {
int T;
scanf("%d", &T);
while ( T-- ) {
scanf("%d%d", &n, &l);
for (int i=1; i<=n; i++) for (int j=1; j<=n; j++)
scanf("%lld", &f[0][i][j]);
if (l == 1) { printf("0\n"); continue; }
l--;
int lev = 0;
for (int p=1; (1<<p) <= l; p++) {
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) {
f[p][i][j] = -inf;
for (int k=1; k<=n; k++)
f[p][i][j] = max(f[p][i][j], f[p-1][i][k] + f[p-1][k][j]);
}
lev++;
}
memset(dp, 0, sizeof(dp));
int cur = 0;
for (int i=lev; i>=0; i--) {
if ((1<<i) > l) continue;
l -= (1<<i);
cur = 1 - cur;
for (int j=1; j<=n; j++) {
dp[cur][j] = -inf;
for (int k=1; k<=n; k++)
dp[cur][j] = max(dp[cur][j], dp[1-cur][k] + f[i][k][j]);
}
}
LL ans = -inf;
for (int j=1; j<=n; j++) ans = max(ans, dp[cur][j]);
printf("%lld\n", ans);
}
return 0;
}