Live2D

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

Descriprtion

  Link.

  在一个含 n 个结点的有向图中,存在边 i,i+1,0,它们不能被删除;还有边 i,j,1 (i<j)i,j,1 (i>j),删除一条边的代价为 ai,j。求使得图无负环的最小删边代价和。

  n500

Solution

  直接将原图看做一个差分约束模型,或说把 无负环 转化成 存在从 1n 的最短路。设 xi 表示 1i 的最短路,那么首先必然有 xixi+1,令 di=xi+1xi0,考虑一条可删除的 i,j{dn1} 影响的情况:

  • i,j,1xixj+1,说明当 k=ij1dk=0 时,此边需要删去;
  • i,j,1xixj1,说明当 k=ji1dk2 时,此边需要删去。

此外已证,dk{0,1} 必然能取到最优方案。所以令 f(i,j) 表示最近一个是 di=1,前一个是 dj=1 时,使结点 1i+1 之间的边符合要求的最小删除代价和,预处理 +11 边删除代价的二维前缀和,枚举前驱状态 f(j,k),可做到 O(n3) 转移。

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

posted @   Rainybunny  阅读(61)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示