[hdu4285 circuits] 插头dp

题意:一个n*m的01矩阵,用刚好k个回路覆盖所有的1,回路之间不能相互包含、交叉,求方法总数。
思路:又1个回路问题,与单回路和多回路问题不同,这题限制了回路个数,那么把回路个数加进状态里面,在转移的时候维护下即可。具体来说,采用8进制表示连通性,用最小表示法将状态编码,dp时用hash保存一个阶段的所有状态。

#include <bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#include "local.h"
#endif // ONLINE_JUDGE

#define pb(x)                   push_back(x)
#define mp(x, y)                make_pair(x, y)
#define all(a)                  (a).begin(), (a).end()
#define mset(a, x)              memset(a, x, sizeof(a))
#define mcpy(a, b)              memcpy(a, b, sizeof(b))
#define up(a, b)                for (int a = 0; a < (b); a ++)
#define down(a, b)              for (int a = b - 1; (a) >= 0; a --)
#define rep(i, a, b)            for (int i = a; i <= (b); i ++)
#define rrep(i, a, b)           for (int i = a; i >= (b); i --)
#define cas()                   int T, cas = 0; cin >> T; while (T --)
#define printCas(ch)            printf("Case #%d:%c", ++ cas, ch)
#define watch(ele)              cout << ele << endl;
#define in(a)                   scanf("%d", &a)

typedef long long ll;
typedef pair<int, int> pii;

template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}

const int mod = 1e9 + 7;
const int N = 15007;

struct HashMap {
    int head[N];
    ll key[N];
    int value[N][40];
    int nxt[N];
    int sz;
    HashMap() {clear();}
    void clear() {
        sz = 0;
        mset(head, -1);
        mset(value, 0);
    }
    int push(ll state, int c, int val) {
        int pos = state % N, i = head[pos];
        for (; ~i; i = nxt[i]) {
            if (key[i] == state) {
                value[i][c] += val;
                if (value[i][c] >= mod) value[i][c] -= mod;
                return i;
            }
        }
        if (i == -1) {
            value[sz][c] = val;
            key[sz] = state;
            nxt[sz] = head[pos];
            head[pos] = sz ++;
            return sz - 1;
        }
    }
};
HashMap dp[2];
int code[15], code2[15];
char used[10], id[10];
int n, m, K, c, row, col, newk, maxid, val, cur;
ll ans;
char s[22][22];

ll encode(int a[]) {
    ans = 0;
    rrep(i, m, 0) {
        ans = ans << 3 | a[i];
    }
    return ans;
}
void decode(int a[], ll state) {
    rep(i, 0, m) {
        a[i] = state & 7;
        state >>= 3;
    }
}
bool chk() {
    c = 0;
    rep(i, 0, col - 1) rep(j, col + 1, m - 1) {
        if (code[i] && code[i] == code[j]) c ^= 1;
    }
    return c == 0;
}
void relax() {
    mset(used, 1);
    c = 1;
    rep(i, 0, m) {
        if (code2[i] && used[code2[i]]) id[code2[i]] = c ++;
        used[code2[i]] = 0;
    }
    rep(i, 0, m) code2[i] = id[code2[i]];
}
void merge() {
    up(i, m) {
        if (i != col && code[i] == code[col]) code2[i] = code[m];
    }
    code2[m] = code2[col] = 0;
    if (code[m] == code[col]) newk ++;
    relax();
}
void turn() {
    code2[m] = code[col];
    code2[col] = code[m];
    relax();
}
void create() {
    maxid = 0;
    up(i, m) umax(maxid, code[i]);
    code2[m] = code2[col] = maxid + 1;
    relax();
}
#define update() dp[cur ^ 1].push(encode(code2), newk, val)
void trans() {
    if (s[row][col] == '*' && (code[m] || code[col])) return;
    if (col == 0 && code[m]) return;
    if (code[m] && code[col]) {
        if (code[m] == code[col]) {
            if (chk()) {
                merge();
                update();
            }
        }
        else {
            merge();
            update();
        }
    }
    if (code[m] && !code[col] || !code[m] && code[col]) {
        update();
        turn();
        update();
    }
    if (!code[m] && !code[col]) {
        if (s[row][col] == '*') update();
        else {
            create();
            update();
        }
    }
}
int work() {
    if (K > n * m / 4) return 0;
    cur = 0;
    dp[0].clear();
    dp[1].clear();
    dp[0].push(0, 0, 1);
    up(i, n) up(j, m) {
        up(k, dp[cur].sz) up(p, K + 1) {
            decode(code, dp[cur].key[k]);
            memcpy(code2, code, sizeof(code2));
            newk = p;
            val = dp[cur].value[k][p];
            row = i;
            col = j;
            if (val) trans();
        }
        dp[cur].clear();
        cur ^= 1;
    }
    return dp[cur].value[dp[cur].push(0, K, 0)][K];
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
    cas() {
        cin >> n >> m >> K;
        up(i, n) scanf("%s", s[i]);
        cout << work() << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值