POJ 1739
这是CDQ大佬在叙述她的插头DP方法时候引用到的例题,运用非常巧妙的对于原图的简单重构,将问题等价转化为简单回路问题。
对于简单回路问题,CDQ大佬在她的论文中详细叙述了如何将问题状态转化为一个括号匹配的问题,思想非常每秒
另外,过程DEBUG时间有点长其实对于刷题找手感来说是不好的,主要是kuangbin大佬的模板不熟练,关于DPBLANK最后一种情况忽视了处理细节
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <stack>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int N= 11;
const int D= 15;
const char PATH= '.';
const char WALL= '#';
const int inc= 2;
const int mask= 3;
const int HASH= 10007;
const int STATE= 1e6+10;
const int L= 1;
const int R= 2;
struct HashMap
{
int head[HASH], next[STATE], size;
LL state[STATE], v[STATE];
void init()
{
size= 0;
memset(head, -1, sizeof(head));
}
void push(const LL st, const LL ans)
{
int h= st%HASH;
for (int i= head[h]; -1!= i; i= next[i]){
if (st== state[i]){
v[i]+= ans;
return;
}
}
v[size]= ans;
state[size]= st;
next[size]= head[h];
head[h]= size++;
}
}hm[2];
int n, m;
char bd[N][N];
int code[D];
// quad
LL Encode(int code[], int m)
{
LL st= 0;
for (int i= m; i>= 0; --i){
st<<= inc;
st|= code[i];
}
return st;
}
void Decode(int code[], int m, LL st)
{
for (int i= 0; i<= m; ++i){
code[i]= mask&st;
st>>= inc;
}
}
void LShfit(int code[], int m)
{
for (int i= m; i> 0; --i){
code[i]= code[i-1];
}
code[0]= 0;
}
char Loc(const int i, const int j) // return the things in the extended board
{
if (i< 1 || i> n || j< 1 || j> m){
return '\0';
}
if (i>= 3 && j>= 3 && j< m-1){
return bd[i-3][j-3];
}
else if (i== 1 || i== n || j== 1 || j== m){
return PATH;
}
else{
return WALL;
}
}
int FMatch(int code[], const int x, const int m) //<- () match
{
stack<int> s;
s.push(code[x]);
int i= x-1, y= 0;
while (!s.empty() && i>= 0){
y= code[i--];
if (!y){
continue;
}
if (s.top()!= y){
s.pop();
}
else{
s.push(y);
}
}
++i;
return 0<= i && m>= i ? i : -1;
}
int BMatch(int code[], const int x, const int m) //-> () match
{
stack<int> s;
s.push(code[x]);
int i= x+1, y= 0;
while (!s.empty() && i<= m){
y= code[i++];
if (!y){
continue;
}
if (s.top()!= y){
s.pop();
}
else{
s.push(y);
}
}
--i;
return 0<= i && m>= i ? i : -1;
}
void DpBlock(int cur, const int i, const int j)
{
int lf= 0, up= 0;
for (int k= 0; k< hm[cur].size; ++k){
Decode(code, m, hm[cur].state[k]);
lf= code[j-1];
up= code[j];
if (lf || up){
continue;
}
code[j-1]= code[j]= 0;
if (j== m){
LShfit(code, m);
}
hm[cur^1].push(Encode(code, m), hm[cur].v[k]);
}
}
void DpBlank(int cur, const int i, const int j)
{
int lf= 0, up= 0;
for (int k= 0; k< hm[cur].size; ++k){
Decode(code, m, hm[cur].state[k]);
lf= code[j-1];
up= code[j];
if (!lf && !up){
if ((i==1 && j== 1) || (i>1 && i< n && j>1 && j<m)){
code[j-1]= L;
code[j]= R;
hm[cur^1].push(Encode(code, m), hm[cur].v[k]);
}
}
else if (lf && up){
if (L== lf){
if (L== up){
int p= BMatch(code, j, m);
code[p]= L;
}
else if (R== up){
if (i!= n || j!= m){
continue;
}
}
}
else if (R== lf){
if (L== up){
// do nothing
}
else if (R== up){
int q= FMatch(code, j-1, m);
code[q]= R;
}
}
code[j-1]= code[j]= 0;
if (j== m){
LShfit(code, m);
}
hm[cur^1].push(Encode(code, m), hm[cur].v[k]);
}
else { // lf or up
int lst= lf ? lf : up;
if (i!= n){ // down
code[j-1]= lst;
code[j]= 0;
if (j== m){
LShfit(code, m);
}
hm[cur^1].push(Encode(code, m), hm[cur].v[k]);
}
if (j!= m){ // ->
code[j-1]= 0;
code[j]= lst;
hm[cur^1].push(Encode(code, m), hm[cur].v[k]);
}
}
}
}
LL Solve()
{
int cur= 0;
LL ans= 0;
n+= 2;
m+= 4; // extend the original board
hm[cur].init();
hm[cur].push(0, 1);
for (int i= 1; i<= n; ++i){
for (int j= 1; j<= m; ++j){
hm[cur^1].init();
if (WALL== Loc(i, j)){
DpBlock(cur, i, j);
}
else if (PATH== Loc(i, j)){
DpBlank(cur, i, j);
}
cur^= 1;
}
}
for (int k= 0; k< hm[cur].size; ++k){
ans+= hm[cur].v[k];
}
return ans;
}
int main()
{
while (~scanf("%d %d", &n, &m) && n){
memset(bd, 0, sizeof(bd));
for (int i= 0; i< n; ++i){
scanf(" %s", bd[i]);
}
printf("%lld\n", Solve());
}
return 0;
}