题解 [AGC036D] Negative Cycle
首先基本可以确定是 DP
但是状态是难以划分的
又是非人力之可为系列
考虑一个图中不存在负环?那就存在最短路啊
因为边权为 0 的那些边的存在,有 \(dis_{i}\geqslant dis_{i+1}\)
因为图中边权都是 \(\pm 1\),所以有 \(dis_{i+1}\geqslant dis_{i}-1\)
那么发现最短路相等的点构成若干个区间,尝试对这个东西(就是最短路的差分数组)做 DP
令 \(f_{i, j}\) 考虑区间 \([1, j]\),最靠右的 \(-1\) 在 \(j\),第二在 \(i\) 且没有负环的最小代价
这个状态可以转移到 \(f_{j, k}\),要删去一些存在会打破当前最短路性质的边
这个可以二维前缀和优化
复杂度 \(O(n^3)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 510
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
ll a[N][N], b[N][N], f[N][N], sum, ans=INF;
signed main()
{
n=read();
memset(f, 0x3f, sizeof(f));
for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) if (i!=j) sum+=(a[i][j]=read()), b[i][j]=a[i][j];
for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) a[i][j]+=a[i][j-1];
for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) a[i][j]+=a[i-1][j];
for (int i=1; i<=n; ++i) {
ll tem=0;
for (int s=1; s<=i; ++s)
for (int t=s+1; t<=i; ++t)
tem+=b[s][t];
f[0][i]=tem;
}
for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) b[i][j]+=b[i][j-1];
for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) b[i][j]+=b[i-1][j];
for (int i=0; i<=n; ++i) {
for (int j=i+1; j<=n; ++j) if (f[i][j]!=INF) {
for (int k=j+1; k<=n; ++k) {
ll tem=0;
tem+=a[k][i]-a[j][i];
tem+=b[k][k]-b[j][k];
f[j][k]=min(f[j][k], f[i][j]+tem);
// printf("f[%d][%d] min= f[%d][%d](%lld)+%lld\n", j, k, i, j, f[i][j], tem);
}
}
}
for (int i=1; i<=n; ++i) ans=min(ans, f[i][n]);
printf("%lld\n", ans);
return 0;
}