Solution -「AGC 036D」「AT 5147」Negative Cycle
阿新 • • 發佈:2021-06-30
\(\mathcal{Descriprtion}\)
Link.
在一個含 \(n\) 個結點的有向圖中,存在邊 \(\lang i,i+1,0\rang\),它們不能被刪除;還有邊 \(\lang i,j,-1\rang~(i<j)\) 和 \(\lang i,j,1\rang~(i>j)\),刪除一條邊的代價為 \(a_{i,j}\)。求使得圖無負環的最小刪邊代價和。
\(n\le500\)。
\(\mathcal{Solution}\)
直接將原圖看做一個差分約束模型,或說把 無負環 轉化成 存在從 \(1\) 到 \(n\) 的最短路。設 \(x_i\) 表示 \(1\)
- \(\lang i,j,-1\rang\):\(x_i\ge x_j+1\),說明當 \(\sum_{k=i}^{j-1}d_k=0\) 時,此邊需要刪去;
- \(\lang i,j,1\rang\):\(x_i\ge x_j-1\),說明當 \(\sum_{k=j}^{i-1}d_k\ge2\) 時,此邊需要刪去。
此外已證,\(d_k\in\{0,1\}\)
\(\mathcal{Code}\)
/* Clearink */ #include <cstdio> #include <cstring> #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i ) #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) typedef long long LL; template<typename Tp> inline Tp imax( const Tp a, const Tp b ) { return a < b ? b : a; } template<typename Tp> inline void chkmin( Tp& a, const Tp b ) { b < a && ( a = b ); } const int MAXN = 500; const LL LINF = 0x3f3f3f3f3f3f3f3f; int n; LL wp[MAXN + 5][MAXN + 5], wn[MAXN + 5][MAXN + 5]; LL f[MAXN + 5][MAXN + 5]; inline LL negS( int a, const int b, int p, const int q ) { a = imax( a, 1 ), p = imax( p, 1 ); return a > p || b > q ? 0 : wn[p][q] - wn[p][b - 1] - wn[a - 1][q] + wn[a - 1][b - 1]; } inline LL posS( int a, const int b, int p, const int q ) { a = imax( a, 1 ), p = imax( p, 1 ); return a > p || b > q ? 0 : wp[p][q] - wp[p][b - 1] - wp[a - 1][q] + wp[a - 1][b - 1]; } int main() { scanf( "%d", &n ); rep ( i, 1, n ) rep ( j, 1, n ) { if ( i < j ) scanf( "%lld", &wn[i][j] ); else if ( i > j ) scanf( "%lld", &wp[i][j] ); wn[i][j] += wn[i - 1][j] + wn[i][j - 1] - wn[i - 1][j - 1]; wp[i][j] += wp[i - 1][j] + wp[i][j - 1] - wp[i - 1][j - 1]; } LL ans = negS( 1, 1, n, n ); memset( f, 0x3f, sizeof f ), f[0][0] = 0; rep ( i, 1, n - 1 ) rep ( j, 0, i - 1 ) { rep ( k, 0, imax( j - 1, 0 ) ) { chkmin( f[i][j], f[j][k] + negS( j + 1, j + 1, i, i ) + posS( j + 2, 1, i + 1, k ) + posS( i + 1, k + 1, i + 1, j ) ); } chkmin( ans, f[i][j] + negS( i + 1, i + 1, n, n ) + posS( i + 2, 1, n, j ) ); } printf( "%lld\n", ans ); return 0; }