正题

题目链接:https://www.luogu.com.cn/problem/P5056


题目大意

\(n*m\)的网格,求有多少条回路可以铺满整个棋盘。


解题思路

插头\(dp\)的,写法是按照题解上的写法。

状态用的是括号匹配,然后用了哈希+邻接表(挂表)还有滚动数组优化空间

然后可以看题解学


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int P=133331;
struct node{
int to,next;
}a[P*2];
int n,m,o,tot,zx,zy,t[2],bit[25],ls[P],S[2][P],v[25][25];
long long ans,dp[2][P];
char st[25];
void Add(int s,long long v){
int x=s%P;
for(int i=ls[x];i;i=a[i].next)
if(S[o][a[i].to]==s)
{dp[o][a[i].to]+=v;return;}
t[o]++;dp[o][t[o]]=v;S[o][t[o]]=s;
a[++tot].to=t[o];a[tot].next=ls[x];ls[x]=tot;
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",st+1);
for(int j=1;j<=m;j++)
if(st[j]=='.'){v[i][j]=1;zx=i;zy=j;}
}
for(int i=0;i<=12;i++)bit[i]=(1<<(i<<1));
t[o]=1;S[o][1]=0;dp[o][1]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=t[o];j++)S[o][j]<<=2;//将右插头移到最左边
for(int j=1;j<=m;j++){
o^=1;tot=t[o]=0;
memset(ls,0,sizeof(ls));
int s,dpl,rpl;long long w;
for(int k=1;k<=t[!o];k++){
s=S[!o][k];w=dp[!o][k];
dpl=(s>>(j<<1))%4;
rpl=(s>>(j-1<<1))%4;
if(!v[i][j]){//障碍
if(!dpl && !rpl)Add(s,w);//不能有插头
}
else if(!dpl && !rpl){//两边都没有插头
if(v[i+1][j]&&v[i][j+1])//开一个左上角插头
Add(s+2*bit[j]+bit[j-1],w);
}
else if(!dpl && rpl){//只有右插头
if(v[i+1][j])Add(s,w);
if(v[i][j+1])Add(s-rpl*bit[j-1]+rpl*bit[j],w);
}
else if(dpl && !rpl){//只有下插头
if(v[i+1][j])Add(s-dpl*bit[j]+dpl*bit[j-1],w);
if(v[i][j+1])Add(s,w);
}
else if(dpl==1&&rpl==1){
int c=1;
for(int p=j+1;p<=m;p++){
if((s>>(p<<1))%4==1)c++;
if((s>>(p<<1))%4==2)c--;
if(!c){Add(s-bit[j]-bit[j-1]-bit[p],w);break;}
} }
else if(dpl==2&&rpl==2){
int c=1;
for(int p=j-2;p>=0;p--){
if((s>>(p<<1))%4==2)c++;
if((s>>(p<<1))%4==1)c--;
if(!c){Add(s-2*bit[j]-2*bit[j-1]+bit[p],w);break;}
}
}
else if(dpl==1&&rpl==2)
Add(s-2*bit[j-1]-bit[j],w);
else if(dpl==2&&rpl==1)
if(i==zx&&j==zy)ans+=w;
}
}
}
printf("%lld\n",ans);
return 0;
}

P5056-[模板]插头dp的更多相关文章

  1. 模板—插头dp(Ural 1519 Formula 1)

    括号表示法: 据说比下一个要快而且灵活. #include<iostream> #include<cstring> #include<cstdio> #define ...

  2. P5056 【模板】插头dp

    \(\color{#0066ff}{ 题目描述 }\) 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? \(\color{#0066ff}{输入格式}\) 第1 ...

  3. 插头DP模板

    /* 插头dp模板 抄的GNAQ 的 括号表示法 */ #include<cstdio> #include<algorithm> #include<cstring> ...

  4. 模板:插头dp

    前言: 严格来讲有关dp的都不应该叫做模板,因为dp太活了,但是一是为了整理插头dp的知识,二是插头dp有良好的套路性,所以姑且还叫做模板吧. 这里先推荐一波CDQ的论文和这篇博客http://www ...

  5. bzoj1814 Ural 1519 Formula 1(插头dp模板题)

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 924  Solved: 351[Submit][Sta ...

  6. LG5056 【模板】插头dp

    题意 题目背景 ural 1519 陈丹琦<基于连通性状态压缩的动态规划问题>中的例题 题目描述 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? 输 ...

  7. 【模板】插头dp

    题目描述 题解: 插头$dp$中经典的回路问题. 首先了解一下插头. 一个格子,上下左右四条边对应四个插头.就像这样: 四个插头. 一个完整的哈密顿回路,经过的格子一定用且仅用了两个插头. 所以所有被 ...

  8. [学习笔记]插头dp

    基于连通性的状压dp 巧妙之处:插头已经可以表示内部所有状态了. 就是讨论麻烦一些. 简介 转移方法:逐格转移,分类讨论 记录状态方法:最小表示法(每次要重新编号,对于一类没用“回路路径”之类的题,可 ...

  9. 插头dp小结

    插头dp: \(A:\)插头dp是什么? \(B:\)一种基于连通性状态压缩的动态规划问题 \(A:\)请问有什么应用呢? \(B:\)各种网格覆盖问题,范围允许状压解决,常用于计算方案数与联通块权值 ...

  10. 插头dp

    插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...

随机推荐

  1. vue项目接口管理,所有接口都在apis文件夹中统一管理

    参考:https://www.codercto.com/a/53432.html 在vue开发中,会涉及到很多接口的处理,当项目足够大时,就需要定义规范统一的接口,如何定义呢? 方法可能不只一种,本文 ...

  2. C++11 unique_ptr智能指针详解

    在<C++11 shared_ptr智能指针>的基础上,本节继续讲解 C++11 标准提供的另一种智能指针,即 unique_ptr 智能指针. 作为智能指针的一种,unique_ptr ...

  3. C语言判断两个值相等

    内置类型比较直接用==判断 字符串比较要用string.h里的函数strcmp(const char *str1,const char *str2)进行比较string.h里的函数strcmp(con ...

  4. Linux 系统下10个查看网络与监听的命令

    下面列出来的10个基础的每个linux用户都应该知道的网络和监控命令.网络和监控命令类似于这些: hostname, ping, ifconfig, iwconfig, netstat, nslook ...

  5. Flink 运行时架构

    参考链接:https://blog.csdn.net/dajiangtai007/article/details/88575553 1.Flink 运行时架构 Flink 运行时架构主要包含几个部分: ...

  6. div 居中显示

    <html lang="en"> <head> <meta charset="UTF-8"> <title>di ...

  7. cmd编译java时常见错误

    中文乱码 在执行javac时出现如图所示问题, 解决方法: 改用 javac -encoding UTF-8执行 找到路径:控制面板--系统和安全--系统--高级系统设置--环境变量--系统变量. 新 ...

  8. java交互Scanner类

    用next方法接收 import java.util.Scanner; public class Demo01 { public static void main(String[] args) { / ...

  9. Python - 面向对象编程 - 新式类和旧式类

    object object 是 Python 为所有对象提供的父类,默认提供一些内置的属性.方法:可以使用 dir 方法查看 新式类 以 object 为父类的类,推荐使用 在 Python 3.x ...

  10. 各种插值法的python实现

    一维插值 插值不同于拟合.插值函数经过样本点,拟合函数一般基于最小二乘法尽量靠近所有样本点穿过.常见插值方法有拉格朗日插值法.分段插值法.样条插值法. 拉格朗日插值多项式:当节点数n较大时,拉格朗日插 ...