插头dp学习笔记

插头,dp,学习,笔记 · 浏览次数 : 3

小编点评

```cpp #include <cstring>#include <iostream>using namespace std;typedef long long ll;const int N = 50000, M = N * 2 + 7;int n, m;int endx, endy; // 记住最后一个有效格子便于封口int g[20][20];int q[2][N]; // 滚动数组,即有效状态在哈希表里面的下标int cnt[N]; // 每次滚动时有效状态的数量int h[2][M]; // 滚动哈希表ll v[2][M]; // 哈希表存的方案数(对应的值)int find(int cur, int x) { // 开放寻址法 求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) { // 在当前滚动的状态内插入state,数量为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 ch; cin >> ch; if (ch == 'X') { endx = i; endy = i; } } cout << 1 << '\n'; return 0;} ```

正文

题目

给你一个 \(n \times m\) 的棋盘,有的格子是障碍,问共有多少条回路满足经过每个非障碍格子恰好一次。

在这里插入图片描述

如图,\(n=m=4\)\((1,1),(1,2)\) 是障碍,共有 \(2\) 条满足要求的回路。

输入格式

第一行包含两个整数 \(n,m\)

接下来 \(n\) 行,每行包含一个长度为 \(m\) 的字符串,字符串中只包含 *.,其中 * 表示障碍格子,. 表示非障碍格子。

输出格式

输出一个整数,表示满足条件的回路数量。

数据范围

\(2 \le n,m \le 12\)

输入样例:

4 4
**..
....
....
....

输出样例:

2

思路

在这里插入图片描述
在这里插入图片描述

实现代码(详细注释)

#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 50000, M = N * 2 + 7;
int n, m;
int endx, endy; // 记住最后一个有效格子便于封口
int g[20][20];
int q[2][N]; // 滚动数组,即有效状态在哈希表里面的下标
int cnt[N]; // 每次滚动时有效状态的数量
int h[2][M]; // 滚动哈希表
ll v[2][M]; // 哈希表存的方案数(对应的值)
int find(int cur, int x) { // 开放寻址法 求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) { // 在当前滚动的状态内插入state,数量为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;
                endx = i, endy = 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) // 处理分界线,0...... -> ......0
            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) { // 找到了和他配对的2
                                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 == endx &&
                    j ==
                        endy) { // 封口,必须是最后一个合法的格子,否则路径不合法
                    res += w;
                }
            }
        }
    }
    cout << res << '\n';
    return 0;
}

与插头dp学习笔记相似的内容:

插头dp学习笔记

## 题目 给你一个 $n \times m$ 的棋盘,有的格子是障碍,问共有多少条回路满足经过每个非障碍格子恰好一次。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f34712c0090d47288ad402cef75795bf.png#pic_center)

[转帖]数据中心常见电源线详细介绍

https://www.cnblogs.com/zhangxinglong/p/14246067.html Power Supply Cord 数据中心常见电源线详细介绍 我们都知道在不同的国家或地区会使用许多不同的插头和插座,当然这里也包括分散在世界各地的数据中心。世界上使用的标准不止一种,不同的

[转帖]15.1. 插件dblink简介

https://help.kingbase.com.cn/v8.6.7.12/development/sql-plsql/ref-extended-plug-in/dblink.html dblink是KingbaseES的一个扩展插件,支持在一个数据库会话中连接到其他Kingbase数据库的模块。

PPT 动画-旋转唱片

插入图片、同心圆 按Shift 先点击背景图片,再点击 同心圆 合并形状,选择相交 设置动画,选择 陀螺旋,持续时间为 8秒, 打开计时窗口,重复为:直到幻灯片末尾

PPT 动画-树叶摆动

插入树叶 插入矩形,长宽放大1倍 树叶和矩形组合

PPT 动画-滚动数字

插入一个文本框,输入 0~9 调整边框大小,使其竖着排列 页面切换,选择平滑

PPT 动画-文字渐入

插入文字,居中对齐 选中文字,将不透明度调成100%,让文字消失不见

DHorse系列文章之maven打包

插件打包 这种方式是平时最常用的,首先要下载并安装maven环境,然后在被打包的项目中引入插件,有各种各样的打包插件,比如springboot自带插件: org.springframework.boot spring-b

可插拔组件设计机制—SPI

SPI 的全称是Service Provider Interface,即提供服务接口;是一种服务发现机制,SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。本篇文章聚焦SPI的使用场景及使用介绍。

插件化工程R文件瘦身技术方案 | 京东云技术团队

随着业务的发展及版本迭代,客户端工程中不断增加新的业务逻辑、引入新的资源,随之而来的问题就是安装包体积变大,前期各个业务模块通过无用资源删减、大图压缩或转上云、AB实验业务逻辑下线或其他手段在降低包体积上取得了一定的成果。