洛谷传送门
BZOJ传送门
题目描述
给出 n ∗ m n*m n∗m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?
输入输出格式
输入格式:
第 1 1 1行, n , m ( 2 ≤ n , m ≤ 12 ) n,m(2\le n,m\le 12) n,m(2≤n,m≤12)
从第 2 2 2行到第 n + 1 n+1 n+1行,每行一段字符串( m m m个字符)," ∗ * ∗“表不能铺线,” . . ."表必须铺
输出格式:
输出一个整数,表示总方案数
输入输出样例
输入样例#1:
4 4
**..
....
....
....
输出样例#1:
2
输入样例#2:
4 4
....
....
....
....
输出样例#2:
6
解题分析
插头DP板子题, 这篇博客讲的很好, 就不再献丑了。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#include <tr1/unordered_map>
#define R register
#define IN inline
#define W while
#define ull unsigned long long
#define ll long long
#define MX 500500
#define uint unsigned int
int n, m, bdn, bdm, now, pre;
std::tr1::unordered_map <int, int> ind;
int tot[2], stat[2][MX], dgt[20];
ll val[2][MX], ans;
bool mp[20][20];
char buf[20][20];
IN void prep()
{
for (R int i = 1; i <= m; ++i) dgt[i] = i << 1;
for (R int i = 1; i <= n; ++i)
for (R int j = 1; j <= m; ++j)
if (buf[i][j] == '.') bdn = i, bdm = j, mp[i][j] = true;
}
IN void insert(R int hs, R ll v)
{
int pos = ind[hs];
if (!pos) pos = ind[hs] = ++tot[now], stat[now][pos] = hs;
val[now][pos] += v;
}
int main(void)
{
int i, j, k, st, lef, up, base, foo, bar, l;
ll v;
scanf("%d%d", &n, &m); now = 0, pre = 1;
for (i = 1; i <= n; ++i) scanf("%s", buf[i] + 1);
tot[0] = 1, val[0][1] = 1; prep();
for (i = 1; i <= n; ++i)
{
for (j = 1; j <= m; ++j)
{
now ^= 1, pre ^= 1;
std::memset(val[now], 0, (tot[now] + 1) * sizeof(ll));
std::memset(stat[now], 0, (tot[now] + 1) * sizeof(int));
ind.clear(); tot[now] = 0;
for (k = 1; k <= tot[pre]; ++k)
{
st = stat[pre][k], v = val[pre][k];
lef = (st >> dgt[j - 1]) % 4, up = (st >> dgt[j]) % 4;
base = st ^ (lef << dgt[j - 1]) ^ (up << dgt[j]);
if (!mp[i][j]) {if ((!lef) && (!up)) insert(st, v);}
else
{
if (lef == 0)
{
if (up == 0)
{
if (mp[i + 1][j] && mp[i][j + 1])
insert(base | (1 << dgt[j - 1]) | (2 << dgt[j]), v);//12
}
else if (up == 1)
{
if (mp[i + 1][j]) insert(base | (1 << dgt[j - 1]), v);//10
if (mp[i][j + 1]) insert(st, v);//01
}
else
{
if (mp[i + 1][j]) insert(base | (2 << dgt[j - 1]), v);//20
if (mp[i][j + 1]) insert(st, v);//02
}
}
else if (lef == 1)
{
if (up == 0)
{
if (mp[i + 1][j]) insert(st, v);//10
if (mp[i][j + 1]) insert(base | (1 << dgt[j]), v);//01
}
else if (up == 1)//11 -> 00, first 2 -> 1
{
foo = 1;
for (l = j + 1; l <= m; ++l)
{
bar = (st >> dgt[l]) % 4;
if (bar == 1) ++foo;
if (bar == 2) --foo;
if (!foo) {insert(base - (1 << dgt[l]), v); break;}
}
}
else//12 -> 00, the end
{
if (i == bdn && j == bdm) ans += v;
}
}
else
{
if (up == 0)
{
if (mp[i + 1][j]) insert(st, v); //20
if (mp[i][j + 1]) insert(base | (2 << dgt[j]), v);//02
}
else if (up == 1) insert(base, v); //21 -> 00
else//22 -> 00, first 1 -> 2
{
foo = 1;
for (l = j - 2; l >= 1; --l)
{
bar = (stat[pre][k] >> dgt[l]) % 4;
if (bar == 1) --foo;
if (bar == 2) ++foo;
if (!foo) {insert(base + (1 << dgt[l]), v); break;}
}
}
}
}
}
}
for (l = 1; l <= tot[now]; ++l) stat[now][l] <<= 2;
}
printf("%lld", ans);
}