1. 程式人生 > 其它 >Solution -「HDU 6875」Yajilin

Solution -「HDU 6875」Yajilin

\(\mathcal{Description}\)

  Link.(HDU 裂開了先放個私鏈 awa。)

  在一個 \(n\times n\) 的方格圖中,格子 \((i,j)\) 有權值 \(w_{i,j}\),現可將一些不相鄰的格子染黑,並保證白格子在四聯通意義下存在哈密頓迴路,方案的價值為染色格子權值之和。求方案的最大價值。

  \(n\le10\),資料組數 \(T\le30\)

\(\mathcal{Solution}\)

  Emmm...插頭 DP 寫得太少了,這題還算比較常規,所以只算記錄一個板子叭。

  令 \(f(i,j,S)\) 表示正要考慮 \((i,j)\) 時,輪廓線為 \(S\)

的最大價值。輪廓上的每條邊有四種狀態:無插頭、左插頭、右插頭、黑格子,大力轉移即可,注意用 hash 儲存狀態。

  複雜度上界是 \(\mathcal O(n^34^{n+1})\),但顯然跑不滿√

\(\mathcal{Code}\)

/*~Rainybunny~*/

#include <cstdio>
#include <cassert>
#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 )

inline void chkmax( int& a, const int b ) { a < b && ( a = b ); }

const int MAXN = 10;
int n, w[MAXN + 5][MAXN + 5];

struct HashTable {
    static const int M = 299987;
    int node, head[M + 5], nxt[M + 5], key[M + 5], val[M + 5];

    inline void clear() {
        rep ( i, 1, node ) head[key[i] % M] = 0;
        node = 0;
    }

    inline void operator () ( const int s, const int v ) {
        int h = s % M, las = 0;
        for ( int i = head[h]; i; i = nxt[las = i] ) {
            if ( key[i] == s ) {
                return chkmax( val[i], v );
            }
        }
        if ( !las ) head[h] = ++node;
        else nxt[las] = ++node;
        key[node] = s, val[node] = v, nxt[node] = 0;
    }
} S[2];

inline int match( const int s, const int k ) {
    int v = s >> k >> k & 3;
    if ( v != 1 && v != 2 ) return -1;
    if ( v == 1 ) {
        int cnt = 1;
        rep ( i, k + 1, n ) {
            if ( int t = s >> i >> i & 3; t == 1 ) ++cnt;
            else if ( t == 2 && !--cnt ) return i;
        }
    } else {
        int cnt = 1;
        per ( i, k - 1, 0 ) {
            if ( int t = s >> i >> i & 3; t == 2 ) ++cnt;
            else if ( t == 1 && !--cnt ) return i;
        }
    }
    return assert( false ), -1;
}

inline bool check( const int s ) {
    rep ( i, 0, n ) {
        if ( ( s >> i >> i & 3 ) && ( s >> i >> i & 3 ) != 3 ) {
            return false;
        }
    }
    return true;
}

inline int solve() {
    S[0].clear(), S[0]( 0, 0 );
    int ret = 0;
    for ( int i = 1, sta = 0; i <= n; ++i ) {
        rep ( j, 1, S[sta].node ) {
            int d = S[sta].key[j] >> n >> n;
            assert( !d || d == 3 );
            ( S[sta].key[j] ^= d << n << n ) <<= 2;
        }

        for ( int j = 1; j <= n; ++j, sta ^= 1 ) {
            S[!sta].clear();
            rep ( k, 1, S[sta].node ) {
                int s = S[sta].key[k], v = S[sta].val[k];
                int pl = s << 2 >> j >> j & 3, pu = s >> j >> j & 3;
                int ql = match( s, j - 1 ), qu = match( s, j );
                s ^= ( pl << j << j >> 2 ) ^ ( pu << j << j );

                if ( !pl && !pu ) { // b
                    S[!sta]( s | 15 << j << j >> 2, v + w[i][j] );
                    if ( i == n && j == n ) chkmax( ret, v + w[i][j] );
                }

                if ( i < n && j < n
                  && ( !pl || pl == 3 ) && ( !pu || pu == 3 ) ) { // rd
                    S[!sta]( s | 9 << j << j >> 2, v );
                }

                if ( pl == 1 && pu == 2 && check( s ) ) { // lu, upd
                    if ( i == n && j == n ) chkmax( ret, v );
                    else if ( i == n && j == n - 1 && !( s >> n >> n & 3 ) ) {
                        chkmax( ret, v + w[n][n] );
                    }
                }

                if ( i < n && ( !pl || pl == 3 )
                  && ( pu == 1 || pu == 2 ) ) { // u-d
                    S[!sta]( s | pu << j << j >> 2, v );
                }

                if ( j < n && ( pl == 1 || pl == 2 )
                  && ( !pu || pu == 3 ) ) { // l-r
                    S[!sta]( s | pl << j << j, v );
                }

                if ( j < n && ( !pl || pl == 3 )
                  && ( pu == 1 || pu == 2 ) ) { // u-r
                    S[!sta]( s | pu << j << j, v );
                }

                if ( i < n && ( pl == 1 || pl == 2 )
                  && ( !pu || pu == 3 ) ) { // l-d
                    S[!sta]( s | pl << j << j >> 2, v );
                }

                if ( ~ql && ql != j && ~qu && qu != j - 1 ) { // lu
                    if ( pl == pu && pl == 1 ) {
                        S[!sta]( s ^ 3 << qu << qu, v );
                    } else if ( pl == pu && pl == 2 ) {
                        S[!sta]( s ^ 3 << ql << ql, v );
                    } else {
                        S[!sta]( s, v );
                    }
                }
            }
        }
    }
    return ret;
}

int main() {
    int T;
    for ( scanf( "%d", &T ); T--; ) {
        scanf( "%d", &n );
        rep ( i, 1, n ) rep ( j, 1, n ) scanf( "%d", &w[i][j] );
        printf( "%d\n", solve() );
    }
    return 0;
}