题意:一个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;
}