看到题目显然是插头\(dp\),但是\(n\)和\(m\)的范围似乎不是很小。我们先不考虑复杂度设一下状态试试:

一共有三个连通分量,我们按照\(1,2,3\)的顺序来表示一下。轮廓线上\(0\)代表没有插头接入,\(x\)说明有第\(x\)个连通分量里的插头接入,需要在这里连下去。

我们设当前格子左边的一位轮廓线为\(b_1\),上边的一位轮廓线为\(b_2\)。

  • 如果\(b_1 = b_2 = 0\):

    • 当前格子可以选择不放。

    • 当前格子也可以向下新建一个\(L\)。

  • 如果\(b1 = 0\)且\(b2 != 0\):

    • 可以连下去。

    • 也可以在这里拐弯向右。

  • 如果\(b1 != 0\)且\(b2 = 0\):

    • 可以向右连下去。

    • 也可以就此结束。

连通分量会出现中断的情况。比如你在很靠上的地方选两个\(L\),又在最下面选了一个\(L\),这时候可能会出现中间某些轮廓线上全都是\(0\),遇到第三个分量的时候不好判断。这里我们在第\(m+1\)位上再放一个数,表示目前已经出现几个连通分量,就容易确定状态的可行性了。

状态和决策都很简单。下面我们看一下复杂度靠谱不靠谱。

一般逐格转移的插头\(dp\)复杂度是\(O(NM*\)状态总数上界\()\)。一条轮廓线上最多有三个连通分量接入,所以用\(0,1,2,3\)四个数四进制表示。每个连通分量只可能接入一次(想一想,为什么),那么可以出现连通分量的选择就有\(C_N^3\)种。考虑三种连通分量各自的编号选择,状态总数就有\(C_N^3 * 4^3=259840\)种。运算次数大概是\(2e8\)左右,开着\(O2\)可以轻松卡过去。

(当然不开\(O2\)略微卡常也可以但是我懒=_=

\(Code\):

#include <bits/stdc++.h>
using namespace std; #define int unsigned long long const int N = 30 + 5;
const int base = 999983;
const int M = 1000000 + 5; int n, m, can_use[N][N]; int las, cur, cnt[2], nxt[M]; int head[M]; int dp[2][M], Hash[2][M]; void update (int zt, int val) {
int _zt = zt % base;
for (int i = head[_zt]; i; i = nxt[i]) {
if (Hash[cur][i] == zt) {
dp[cur][i] += val; return;
}
}
nxt[++cnt[cur]] = head[_zt];
head[_zt] = cnt[cur];
Hash[cur][cnt[cur]] = zt;
dp[cur][cnt[cur]] = val;
} int get_val (int zt) {
int _zt = zt % base;
for (int i = head[_zt]; i; i = nxt[i]) {
if (Hash[cur][i] == zt) {
return dp[cur][i];
}
}
return 0;
} int get_wei (int zt, int wei) {
return (zt >> (wei * 2)) % 4;
} int alt_wei (int zt, int wei, int val) {
return zt - ((get_wei (zt, wei) - val) << (wei * 2));
} void change_row () {
for (int i = 1; i <= cnt[cur]; ++i) {
int &zt = Hash[cur][i];
for (int k = m; k >= 1; --k) {
zt = alt_wei (zt, k, get_wei (zt, k - 1));
}
zt = alt_wei (zt, 0, 0);
}
} void print_zt (int zt) {
for (int k = 0; k<= m + 1; ++k) {
cout << get_wei (zt, k) << " ";
}
} void print (int x, int y) {
cout << "r = " << x << " c = " << y << endl;
for (int i = 1; i <= cnt[cur]; ++i) {
cout << "zt = ";
print_zt (Hash[cur][i]);
cout << "dp = " << dp[cur][i] << endl;
}
} int solve () {
update (0, 1);
// print (0, 0);
for (int i = 1; i <= n; ++i) {
change_row ();
for (int j = 1; j <= m; ++j) {
las = cur, cur ^= 1, cnt[cur] = 0;
memset (head, 0, sizeof (head));
for (int k = 1; k <= cnt[las]; ++k) {
int zt = Hash[las][k];
int b1 = get_wei (zt, j - 1);
int b2 = get_wei (zt, j - 0);
int val = dp[las][k];
// print_zt (zt); cout << endl;
// cout << "b1 = " << b1 << " b2 = " << b2 << endl;
if (!can_use[i][j]) {
if (!b1 && !b2) {
update (zt, val);
}
} else {
if (b1 == 0 && b2 == 0) {
int b = get_wei (zt, m + 1), _zt = zt;
if (b < 3 && can_use[i + 1][j]) {
_zt = alt_wei (_zt, m + 1, b + 1); // 新建连通分量
_zt = alt_wei (_zt, j - 1, b + 1); // b1 那一位改为新分量编号
// print_zt (zt); cout << " -> "; print_zt (_zt); cout << endl;
update (_zt, val);
}
update (zt, val); // 这个格子不占用
}
if (b1 == 0 && b2 != 0) {
if (can_use[i + 1][j]) {
int _zt = zt;
_zt = alt_wei (_zt, j - 1, b2);
_zt = alt_wei (_zt, j - 0, 0);
// 0_b2 -> b2_0
// print_zt (zt); cout << " -> "; print_zt (_zt); cout << endl;
update (_zt, val);
}
if (can_use[i][j + 1]) {
update (zt, val);
// 0_b2 -> 0_b2
}
}
if (b1 != 0 && b2 == 0) {
if (can_use[i][j + 1]) {
int _zt = zt;
_zt = alt_wei (_zt, j - 1, 0);
_zt = alt_wei (_zt, j - 0, b1);
// b1_0 -> 0_b1 // print_zt (zt); cout << " -> "; print_zt (_zt); cout << endl;
update (_zt, val);
}
int _zt = alt_wei (zt, j - 1, 0);
// b1_0 -> 0_0
// print_zt (zt); cout << " -> "; print_zt (_zt); cout << endl;
update (_zt, val);
}
}
}
// print (i, j);
}
}
int fin = alt_wei (0, m + 1, 3);
return get_val (fin);
} signed main () {
// freopen ("data.in", "r", stdin);
// freopen ("data.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
int ch = getchar ();
if (ch != '.' && ch != '#') {
ch = getchar ();
}
if (ch == '.') can_use[i][j] = true;
// cout << can_use[i][j] << " ";
}
// cout << endl;
}
cout << solve () << endl;
}

Luogu P3170 [CQOI2015]标识设计 状态压缩,轮廓线,插头DP,动态规划的更多相关文章

  1. POJ2411Mondriaan's Dream(DP+状态压缩 or 插头DP)

    问题: Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after prod ...

  2. POJ3254Corn Fields (状态压缩or插头DP)

    Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; ...

  3. POJ 2923 【01背包+状态压缩/状压DP】

    题目链接 Emma and Eric are moving to their new house they bought after returning from their honeymoon. F ...

  4. ZJOI 2009 多米诺骨牌(状态压缩+轮廓线+容斥)

    题意 https://www.lydsy.com/JudgeOnline/problem.php?id=1435 思路 一道很好的状压/容斥题,涵盖了很多比较重要的知识点. 我们称每两行间均有纵跨.每 ...

  5. [luogu]P3959 宝藏[NOIP][状态压缩DP]

    [luogu]P3959 宝藏[TREASURE] 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的 ...

  6. HDU 5025 状态压缩蛇+bfs+dp

    题目大意:孙悟空要找到一条花费时间最短的路径,路上为S的代表有蛇,经过需多花一分钟,其他情况下都是走过花费一分钟,但数字必须依次得到,最后到了唐僧处,可以经过也可以救出,救出前提是得到所有种类的钥匙 ...

  7. uva10944 状态压缩bfs or DP

    又是一道状压搜索,题解有的是状压DP做的目前不会日后补 写好了以后一直蜜汁WA,看别人代码把判断再次回到原点的语句写在了Q.pop()之后而不是for里,对我也是一种启发吧这样写确实有好处比如起点就是 ...

  8. [ACM_动态规划] 轮廓线动态规划——铺放骨牌(状态压缩1)

    Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, af ...

  9. 洛谷P2258 子矩阵 题解 状态压缩/枚举/动态规划

    作者:zifeiy 标签:状态压缩.枚举.动态规划 题目链接:https://www.luogu.org/problem/P2258 这道题目状态压缩是肯定的,我们需要用二进制来枚举状态. 江湖上有一 ...

随机推荐

  1. jenkins提示反向代理设置有误

    jenkins提示反向代理设置有误 参照地址 https://www.cnblogs.com/yhleng/p/7594892.html 分析:是junkins的url地址填错了 解决: 系统管理-- ...

  2. jdbc简单连接oracle数据库

    package com.shangsheng; import java.sql.*; public class UserOracle { public static void main(String[ ...

  3. argparse:命令行参数解析详解

    简介# 本文介绍的是argparse模块的基本使用方法,尤其详细介绍add_argument内建方法各个参数的使用及其效果. 本文翻译自argparse的官方说明,并加上一些笔者的理解 Copy im ...

  4. 【MM系列】SAP S/4 HANA 1511的BP角色创建及供应商数据的创建方法

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP S/4 HANA 1511的 ...

  5. Egret入门学习日记 --- 第二篇 (书籍的选择 && 书籍目录 && 书中 3.3 节 内容)

    第二篇 (书籍的选择 && 书籍目录 && 书中 3.3 节 内容) 既然选好了Egret,那我就要想想怎么学了. 开始第一步,先加个Q群先,这不,拿到了一本<E ...

  6. 关于mysql8.0及以上版本连接navicat时候报错(密码加密方式需要修改)

    首先这个原因是因为MySQL版本的密码加密方式变了,要把它修改成以前的方式(因为,navicat不支持这种方式) 1:先进入mysql: mysql -uroot -p123456; 2:查询密码加密 ...

  7. 【神经网络与深度学习】Caffe使用step by step:caffe框架下的基本操作和分析

    caffe虽然已经安装了快一个月了,但是caffe使用进展比较缓慢,果然如刘老师说的那样,搭建起来caffe框架环境比较简单,但是完整的从数据准备->模型训练->调参数->合理结果需 ...

  8. windows编程 使用C++实现多线程类

    有时候我们想在一个类中实现多线程,主线程在某些时刻获得数据,可以“通知”子线程去处理,然后把结果返回.下面的实例是主线程每隔2s产生10个随机数,将这10随机数传给多线程类,让它接收到数据后马上打印出 ...

  9. NFC读写器调试总结20191203

    以下为NFC读写器调试经验总结: 1.读写器部分,从TX1/TX2输出的13.56MHZ信号主要由L0/C0构成低通滤波器,用于滤除13.56MHZ的高次谐波,取值L0=1UH,C0=47PF时候,谐 ...

  10. Websocket --(2)实现

    首先声明,本篇博文参考文章 https://blog.csdn.net/jack_eusong/article/details/79064081 主要在于理解和自己动手搭建环境,自己搭建的过程中会发生 ...