AtCoder AGC036D負のサイクル(图论、DP)

トピックリンク

https://atcoder.jp/contests/agc036/tasks/agc036_d

問題の解決策

これは、ああの外に考える方法です。唖然シリーズ。

最初のステップは、重要な変換である:任意の負の環が存在しない場合にマップすることを意味しますか?
負環最短経路が存在しない、我々は各点に重みを割り当てることができる\(P_Iが\) に対応する(1 \)は\点から点への最短数\(1 \)は数字開始します)任意エッジ満足\((i、j)を\ ) している\ \(GE P_I + W(I、J \ p_jが))
その後、我々はせ\(Q_I = P_I-P_を{Iは+ 1} \) 次いで右側であるため、(1 \)を\または\( - 1 \)とが削除できない\(0 \)側、明らかに\(Q \)配列値は\(0 \)または\(1 \)
制約は次のようになる。各エッジのために\((i、j)は\ (I> J)\) している(\ \和^ {I- 1} _ {K = I} q_k \ル1 \) 各エッジのために\((i、j)は\ (I <jの)\) している(\ \ SUM 1} ^ {J-K = {I} GE \ _ q_k。1 \)
問題は、その後に変換されます:あなたは、各与える\を(1 \)する((N-1)\ \ ) ポイント\(Q_I \)が割り当て\(0 \)または\(1 \)の重みを、その後の総コストを最小限に抑えるために、すべてのエッジは、制約条件を満たしていない削除!
神は、これは神もそれで......

その後容易DP、セットで\(DP [i]は[J ] \) を表し従来の配置\(Iは\)ビット\(Q \)の値を、力指令\(Q_I = 1 \) いずれかを\(1 \)位置である\(J \)
次に検討列挙\(K \) \(DP [I] [J] \)に移した\(DP [K] [I ] \) ない法的削除縁ながら
ため\(> B \)エッジ\は((B)\) 全て満たす除去する\(J <B \ルI <X <\) エッジを
するため\(<B \)エッジ\((B)\) 全て満たす除去する\(jは<私は<< B \ルX \) の側面
と、この接頭辞を使用することは容易であり、二次元の最適化を、時間の複雑\(O(N ^ 3)\)

人間の知恵をああああああ......

コード

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#define llong long long
using namespace std;

inline int read()
{
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x;
    return -x;
}

const int N = 500;
llong a[N+3][N+3];
llong s[2][N+3][N+3];
llong dp[N+3][N+3];
int n;

void update(llong &x,llong y) {x = x<y?x:y;}

llong getsum(int typ,int lx,int rx,int ly,int ry)
{
    return s[typ][rx][ry]-s[typ][lx-1][ry]-s[typ][rx][ly-1]+s[typ][lx-1][ly-1];
}

int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(j==i) continue;
            scanf("%lld",&a[i][j]);
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(i<j) {s[0][i][j] = a[i][j];}
            s[0][i][j] += s[0][i][j-1];
        }
        for(int j=1; j<=n; j++) s[0][i][j] += s[0][i-1][j];
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(i>j) {s[1][i][j] = a[i][j];}
            s[1][i][j] += s[1][i][j-1];
        }
        for(int j=1; j<=n; j++) s[1][i][j] += s[1][i-1][j];
    }
    memset(dp,42,sizeof(dp)); 
    dp[0][0] = 0ll;
    for(int i=0; i<=n; i++)
    {
        for(int j=0; j<max(i,1); j++)
        {
            for(int k=i+1; k<=n; k++)
            {
                llong tmp = dp[i][j]+getsum(1,k+1,n,j+1,i)+getsum(0,i+1,k,i+1,k);
                update(dp[k][i],tmp);
            }
        }
    }
    llong ans = dp[n][1];
    for(int i=1; i<=n; i++) update(ans,dp[n][i]);
    printf("%lld\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/suncongbo/p/11298504.html