没有负环可以理解为能够给第
i
i
i个点一个距离值
d
i
d_i
di。由于
i
i
i到
i
+
1
i+1
i+1有
0
0
0边,因此
d
i
≥
d
i
+
1
d_i\geq d_{i+1}
di≥di+1,且由于边权绝对值不超过
1
1
1,因此
d
i
≤
d
i
+
1
+
1
d_i\leq d_{i+1}+1
di≤di+1+1。为了使距离值合法,对于
j
<
i
j<i
j<i,若
d
j
=
d
i
d_j=d_i
dj=di,不能有
−
1
-1
−1的边,若
d
j
>
d
i
+
1
d_j>d_i+1
dj>di+1,不能有
1
1
1的边,且若
d
i
=
d
i
−
1
−
1
d_i=d_{i-1}-1
di=di−1−1,必须有
d
j
=
d
i
+
1
d_j=d_i+1
dj=di+1到
i
i
i的
−
1
-1
−1的边。
考虑计数,设
F
[
i
]
[
j
]
F[i][j]
F[i][j]表示考虑到
i
i
i,
d
j
=
d
j
+
1
=
.
.
.
=
d
i
d_j=d_{j+1}=...=d_i
dj=dj+1=...=di且
d
i
≠
d
j
−
1
d_i\neq d_{j-1}
di=dj−1,转移枚举一个
k
>
i
k>i
k>i,使得
d
i
+
1
=
d
i
+
2
=
.
.
.
=
d
k
=
d
i
−
1
d_{i+1}=d{i+2}=...=d_k=d_i-1
di+1=di+2=...=dk=di−1,乘上贡献即可。
时间复杂度
O
(
N
3
)
\mathcal O(N^3)
O(N3)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline void update(ll &x,ll y) {
x=max(x,y);
}
int num[505][505];
ll sum1[505][505],sum2[505][505];
void pre(int n) {
for(int i=0;i<=n;i++)
for(int j=i+1;j<=n;j++) sum1[i][j]=sum1[i][j-1]+num[i][j];
for(int i=n;i>=0;i--)
for(int j=i+1;j<=n;j++) sum1[i][j]=sum1[i+1][j]+sum1[i][j];
for(int i=0;i<=n;i++)
for(int j=i+1;j<=n;j++) sum2[i][j]=sum2[i][j-1]+num[j][i];
for(int i=n;i>=0;i--)
for(int j=i+1;j<=n;j++) sum2[i][j]=sum2[i+1][j]+sum2[i][j];
}
ll f[505][505];
void dp(int n) {
for(int i=0;i<n;i++)
for(int j=0;j<=i;j++)
for(int k=i+1;k<=n;k++)
update(f[k][i],f[i][j]+sum1[0][k]-sum1[0][i]-sum1[i+1][k]+sum2[j+1][k]-sum2[j+1][i]);
}
int main() {
int n;
scanf("%d",&n);
ll s=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if (i!=j) {
scanf("%d",&num[i][j]);
s+=num[i][j];
}
pre(n);
dp(n);
ll ans=0;
for(int i=0;i<=n;i++) update(ans,f[n][i]);
printf("%lld\n",s-ans);
return 0;
}