1. 程式人生 > 其它 >Solution -「AGC 036D」「AT 5147」Negative Cycle

Solution -「AGC 036D」「AT 5147」Negative Cycle

\(\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\)

\(i\) 的最短路,那麼首先必然有 \(x_i\ge x_{i+1}\),令 \(d_i=x_{i+1}-x_i\ge0\),考慮一條可刪除的 \(\lang i,j\rang\)\(\{d_{n-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\}\)

必然能取到最優方案。所以令 \(f(i,j)\) 表示最近一個是 \(d_i=1\),前一個是 \(d_j=1\) 時,使結點 \(1\sim i+1\) 之間的邊符合要求的最小刪除代價和,預處理 \(+1\)\(-1\) 邊刪除代價的二維字首和,列舉前驅狀態 \(f(j,k)\),可做到 \(\mathcal O(n^3)\) 轉移。

\(\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;
}