难度很大,推荐 直接写暴力+剪枝
插头dp是由《基于连通性状态压缩的动态规划问题》而产生的
eg 模板题
对于每个格子而言只有
C
2
4
=
6
C_2^4 =6
C24=6种情况,而只会考虑每条小边上的情况,记录是否有边出来,其次应该维护连通性,那几个出来的边属于一个连通块
记录连通块的方法1、最小表示法,则此图的情况为
2、括号表示法(没有最小表示法通用)
由于本题是一个回路,则如有往上的边则一定存在与之配对且向下的边
性质1:两两配对
性质2:路径间不可能交叉
由这两个性质可以视为一个括号序列,则一个三进制的状态就可以表示(‘(’:1 ‘’:0 ‘)’:2)
此处使用闫氏dp分析法分析
一共有8种情况😀
需要用到哈希表,滚动数组和数组存储有效状态
代码不是太复杂
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 50000, M = N * 2 + 7;
int n, m, end_x, end_y;
int g[20][20], q[2][N], cnt[N];
int h[2][M];
LL v[2][M];
int find(int cur, int x)
{
int t = x % M;
while (h[cur][t] != -1 && h[cur][t] != x)
if ( ++ t == M)
t = 0;
return t;
}
void insert(int cur, int state, LL w)
{
int t = find(cur, state);
if (h[cur][t] == -1)
{
h[cur][t] = state, v[cur][t] = w;
q[cur][ ++ cnt[cur]] = t;
}
else v[cur][t] += w;
}
int get(int state, int k) // 求第k个格子的状态,四进制的第k位数字
{
return state >> k * 2 & 3;
}
int set(int k, int v) // 构造四进制的第k位数字为v的数
{
return v * (1 << k * 2);
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
{
char str[20];
scanf("%s", str + 1);
for (int j = 1; j <= m; j ++ )
if (str[j] == '.')
{
g[i][j] = 1;
end_x = i, end_y = j;
}
}
LL res = 0;
memset(h, -1, sizeof h);
int cur = 0;
insert(cur, 0, 1);
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= cnt[cur]; j ++ )
h[cur][q[cur][j]] <<= 2;
for (int j = 1; j <= m; j ++ )
{
int last = cur;
cur ^= 1, cnt[cur] = 0;
memset(h[cur], -1, sizeof h[cur]);
for (int k = 1; k <= cnt[last]; k ++ )
{
int state = h[last][q[last][k]];
LL w = v[last][q[last][k]];
int x = get(state, j - 1), y = get(state, j);
if (!g[i][j])
{
if (!x && !y) insert(cur, state, w);
}
else if (!x && !y)
{
if (g[i + 1][j] && g[i][j + 1])
insert(cur, state + set(j - 1, 1) + set(j, 2), w);
}
else if (!x && y)
{
if (g[i][j + 1]) insert(cur, state, w);
if (g[i + 1][j]) insert(cur, state + set(j - 1, y) - set(j, y), w);
}
else if (x && !y)
{
if (g[i][j + 1]) insert(cur, state - set(j - 1, x) + set(j, x), w);
if (g[i + 1][j]) insert(cur, state, w);
}
else if (x == 1 && y == 1)
{
for (int u = j + 1, s = 1;; u ++ )
{
int z = get(state, u);
if (z == 1) s ++ ;
else if (z == 2)
{
if ( -- s == 0)
{
insert(cur, state - set(j - 1, x) - set(j, y) - set(u, 1), w);
break;
}
}
}
}
else if (x == 2 && y == 2)
{
for (int u = j - 2, s = 1;; u -- )
{
int z = get(state, u);
if (z == 2) s ++ ;
else if (z == 1)
{
if ( -- s == 0)
{
insert(cur, state - set(j - 1, x) - set(j, y) + set(u, 1), w);
break;
}
}
}
}
else if (x == 2 && y == 1)
{
insert(cur, state - set(j - 1, x) - set(j, y), w);
}
else if (i == end_x && j == end_y)
res += w;
}
}
}
cout << res << endl;
return 0 ;
}
之后随缘更新吧。