【插头DP】Yajilin – 20HDU多校9Y

传送门

题意是说给一个网格,每个格子有一个权值,选择其中一些格子涂黑,要求黑色直接不能临边。然后还需要找到一条哈密顿回路。

问如何选择黑色的格子使得权值最大。

插头DP,0表示无插头,1、2表示对应联通分量的插头,3表示黑色格子的插头。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
const int N = 100007;
int n;
int a[16][16], state[2][N], dp[2][N], now;
int G(int k, int x) {return (k >> (x << 1)) & 3;} // 轮廓线k的第x位状态
int F(int k, int x) {return k << (x << 1);} // 编码第x位的状态k
// unordered_map<int, int> st;
int fst[N], pre[N], mk[N], mt, tot;
void init()
{
    mt++; tot = 0;
}
void insert(int s, int w)
{
    int sp = s % N;
    if(mk[sp] != mt) mk[sp] = mt, fst[sp] = -1;
    for(int i = fst[sp]; ~i; i = pre[i])
    {
        if(state[now][i] == s) 
        {
            dp[now][i] = max(dp[now][i], w);
            return ;
        }
    }
    state[now][tot] = s;
    dp[now][tot] = w;
    pre[tot] = fst[sp]; fst[sp] = tot++;
}
int ans = 0;
void solve(int i, int j)
{
    int t = max(1, tot);
    init();
    for(int k = 0; k < t; k++)
    {
        int s = state[1 - now][k];
        int val = dp[1 - now][k];
        int p = G(s, j - 1), q = G(s, j);
        // 原状态s[i] xor 新状态 c ^ (s[i]) = c 
        if(p == 0 && q == 0) insert(s ^ F(3, j - 1) ^ F(3, j), val + a[i][j]); // 情况1 新建联通分量
        if((p == 0 || p == 3) && (q == 0 || q == 3)) // 情况3 保持原有联通分量
        {
            if(i + 1 <= n && j + 1 <= n) insert(s ^ F(1 ^ p, j - 1) ^ F(2 ^ q, j), val);
        } 
        else if(p == 0 || p == 3)
        {
            if(j + 1 <= n) insert(s ^ F(p, j - 1), val);
            if(i + 1 <= n) insert(s ^ F(p ^ q, j - 1) ^ F(q, j), val);
        }
        else if(q == 0 || q == 3)
        {
            if(i + 1 <= n) insert(s ^ F(q, j), val);
            if(j + 1 <= n) insert(s ^ F(q ^ p, j) ^ F(p, j - 1), val);
        }
        else if(p == 1 && q == 1) // 情况2 合并联通分量
        {
            int tmp = 1;
            for(int l = j + 1; l <= n; l++)
            {
                if(G(s, l) == 1) tmp++; else if(G(s, l) == 2) tmp--;
                if(tmp == 0) {insert(s ^ F(p, j - 1) ^ F(q, j) ^ F(2 ^ 1, l), val); break;}
            }
        }
        else if(p == 2 && q == 2)
        {
            int tmp = 1;
            for(int l = j - 2; l > 0; l--)
            {
                if(G(s, l) == 1) tmp--; else if(G(s, l) == 2) tmp++;
                if(tmp == 0) {insert(s ^ F(p, j - 1) ^ F(q, j) ^ F(1 ^ 2, l), val); break;}
            }
        }
        else if(p == 2 && q == 1)
        {
            insert(s ^ F(p, j - 1) ^ F(q, j), val);
        }
        else 
        {
            if(i == n && j == n) ans = max(ans, val);
            if(i == n && j == n - 1 && G(s, n) == 0) ans = max(ans, val + a[n][n]);
        }
    }
}
int main()
{
    // freopen("input.txt", "r", stdin);
    // time_t startt = clock();

    cin.tie(0); cout.tie(0); ios::sync_with_stdio(0);
    int cas; cin >> cas;
    while(cas--)
    {
        cin >> n;
        ans = 0; now = 0; state[0][0] = 0; dp[0][0] = 0;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++) cin >> a[i][j];

        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                now = 1 - now;
                memset(state[now], 0, sizeof state[now]);
                memset(dp[now], 0, sizeof dp[now]);
                solve(i, j);
            }
            for(int k = 0; k < tot; k++) 
            {
                state[now][k] <<= 2; 
                state[now][k]&=(F(1,n+1)-1); // 删掉第n+1位,使得维护的Hash表状态有效
            }
        }
        cout << ans << endl;
    }    
    // cerr << "~ #" << " done! time : " << (double)(clock()-startt) << " ms" << endl;
    // cerr << "~ #" << " done! time : " << (double)(clock()-startt)/CLOCKS_PER_SEC << " s" << endl;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注