题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1814

普通的插头 DP 。但是调了很久。注意如果合并两个 1 的话,不是 “把向右第一个 2 该成 1 ”,而是 “把向右第一个没有与 1 匹配的 2 改成 1 ”。

原来获取哈希值是用字符串哈希的方法,遍历12个位置;太慢。直接对某数取模作为哈希值,手写哈希表保证不会找错状态。大概 1e5 个状态?

在转移的时候看一下下方和右边有没有障碍、只做合法的转移的话,取答案的时候就不用在判断 “当前两个位置是 1 和 2 ”之外再判断 “其余位置都是 0 ” 了。

自己写的是 “如果当前位置是结束位置且当前两个插口是 1 和 2 就输出答案并 break ” 。这样无解的时候要手动输出 0 。

滚动数组。并且只遍历有效的状态。方法是用手写队列存 “得到转移” 的状态,用 vis 判断该状态是否已经在队列里;把下一层的队列做好之后,遍历下一层(不是这一层)的队列把 vis 清空即可。

注意 long long 。

哈希表的映射方式是:原状态 -> 哈希值 -> ++tot 地分配空间 -> 原状态 。“ -> ” 就是要记下的对应关系。因为哈希值要用数组记它对应哪个位置,所以哈希值不宜太大。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=,M=1e5+;//mention
int n,m,bin[N],q[][M],t[]; ll dp[][M];
bool b[N][N],vis[M],en[N][N];
namespace H{
const int md=1e6+;//
int hd[md+],xnt,nxt[M],vl[M];
int Ps(int s)
{
int h=s%md;
for(int i=hd[h];i;i=nxt[i])
if(vl[i]==s){return i;}
vl[++xnt]=s; nxt[xnt]=hd[h]; hd[h]=xnt;
return xnt;
}
}
int get(int cr,int j){ return (cr&(bin[j+]-bin[j]))>>(*j);}
void cz(int d,bool v){ if(!vis[d]) vis[d]=,q[v][++t[v]]=d;}
void solve()
{
bin[]=; int lm=m+;
for(int i=;i<=lm;i++)bin[i]=bin[i-]<<;
bool flag=;
for(int i=n;i&&!flag;i--)
for(int j=m;j;j--)
if(!b[i][j]){en[i][j]=flag=;break;}
bool u=,v=; flag=;
dp[u][H::Ps()]=; q[u][++t[u]]=;
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
for(int c=;c<=t[u];c++)
{
int cr=H::vl[q[u][c]];ll tp=dp[u][q[u][c]];//ll!!!
int d0=get(cr,j-), d1=get(cr,j), t0,t1;
if(b[i][j])
{
if(!d0&&!d1)
{ t0=H::Ps(cr); cz(t0,v); dp[v][t0]+=tp;}
continue;
}
if(en[i][j])
{
if(d0==&&d1==)
{ printf("%lld\n",tp);flag=;break;}
continue;
}
if((!d0&&d1)||(!d1&&d0))
{
t0=cr; t1=cr+d1*bin[j-]-d0*bin[j-]+d0*bin[j]-d1*bin[j];
if(i<n&&!b[i+][j])
{if(d0){t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;}
else{t1=H::Ps(t1); cz(t1,v); dp[v][t1]+=tp;}}
if(j<m&&!b[i][j+])
{if(d0){t1=H::Ps(t1); cz(t1,v); dp[v][t1]+=tp;}
else{t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;}}
continue;
}
if(!d0&&!d1&&i<n&&j<m&&!b[i+][j]&&!b[i][j+])
{
t0=cr+bin[j-]+*bin[j];
t0=H::Ps(t0); cz(t0,v);
dp[v][t0]+=tp; continue;
}
if(d0==&&d1==)
{
t0=cr-bin[j-]-bin[j];
for(int p=j+,top=,d;p<=m;p++)
{
d=get(t0,p);
if(d==)top++; else if(d==&&top)top--;
else if(d==){t0-=bin[p];break;}
}
t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp; continue;
}
if(d0==&&d1==)
{
t0=cr-*bin[j-]-*bin[j];//2*!!!
for(int p=j-,top=,d;p>=;p--)
{
d=get(t0,p);
if(d==)top++; else if(d==&&top)top--;
else if(d==){t0+=bin[p];break;}
}
t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;
continue;
}
if(d0==&&d1==)
{
t0=cr-*bin[j-]-bin[j];
t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp; continue;
}
}
if(flag)break;
for(int c=;c<=t[u];c++)dp[u][q[u][c]]=;
for(int c=;c<=t[v];c++)vis[q[v][c]]=;//v not u!!!
t[u]=; swap(u,v);
}
if(flag)break;
for(int c=;c<=t[u];c++)
{
int cr=H::vl[q[u][c]];ll tp=dp[u][q[u][c]];//ll!!!
if(get(cr,m))continue;
int d=cr<<;
d=H::Ps(d); cz(d,v); dp[v][d]=tp;
}
for(int c=;c<=t[u];c++)dp[u][q[u][c]]=;
for(int c=;c<=t[v];c++)vis[q[v][c]]=;
t[u]=; swap(u,v);
}
if(!flag)puts("");///
}
int main()
{
scanf("%d%d",&n,&m); char ch[N];
for(int i=;i<=n;i++)
{
scanf("%s",ch+);
for(int j=;j<=m;j++)
b[i][j]=(ch[j]=='*');
}
solve();
return ;
}

bzoj 1814 Ural 1519 Formula 1 ——插头DP的更多相关文章

  1. bzoj 1814 Ural 1519 Formula 1 插头DP

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

  2. bzoj 1814: Ural 1519 Formula 1 插头dp经典题

    用的括号序列,听说比较快. 然并不会预处理,只会每回暴力找匹配的括号. #include<iostream> #include<cstdio> #include<cstr ...

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

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

  4. 【BZOJ1814】Ural 1519 Formula 1 插头DP

    [BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...

  5. Ural 1519 Formula 1 插头DP

    这是一道经典的插头DP单回路模板题. 用最小表示法来记录连通性,由于二进制的速度,考虑使用8进制. 1.当同时存在左.上插头的时候,需要判断两插头所在连通块是否相同,若相同,只能在最后一个非障碍点相连 ...

  6. bzoj 1814: Ural 1519 Formula 1【插头dp】

    设f[i][j][s]为轮廓线推到格子(i,j),状态为s的方案数 括号表示一段线的左端和右端,表示成左括号和右括号,状压的时候用1和2表示,0表示已经闭合 下面的蓝线是黄色格子的轮廓线,dp转移要把 ...

  7. BZOJ1814: Ural 1519 Formula 1(插头Dp)

    Description Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic gam ...

  8. 【Ural】1519. Formula 1 插头DP

    [题目]1519. Formula 1 [题意]给定n*m个方格图,有一些障碍格,求非障碍格的哈密顿回路数量.n,m<=12. [算法]插头DP [题解]<基于连通性状态压缩的动态规划问题 ...

  9. 【BZOJ1814】Ural 1519 Formula 1 (插头dp)

    [BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...

随机推荐

  1. 大数据新手之路一:安装JDK

    Ubuntu16.04 1.下载jdk-8u192-linux-x64.tar.gz https://www.oracle.com/technetwork/java/javase/downloads/ ...

  2. spring cloud 配置文件application.yml和bootstrap.yml 的定位,区别和联系

    最近在启用springcloud配置中心server的东西,在整理属性资源的时候,突然发现:用了这么久的springboot,为什么会配置两个属性文件同时存在(application.yml/prop ...

  3. http与rfc

    超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准.设计HTTP最初的目的是为了提供一种发布和接 ...

  4. Docker Image管理学习笔记,ZT

    Docker Image管理学习笔记 http://blog.csdn.net/junjun16818/article/details/38423391

  5. bzoj 5068: 友好的生物

    大意: n个生物, 每个生物有k种属性, 友好度通过下式计算. , C为给定非负数组, 求友好度最大值. k比较小, 求的是最大值并且$C_i$非负, 所以可以暴力枚举正负情况去绝对值号. #incl ...

  6. 『Python CoolBook』使用ctypes访问C代码_上_用法讲解

    一.动态库文件生成 源文件hello.c #include "hello.h" #include <stdio.h> void hello(const char *na ...

  7. 『TensorFlow』读书笔记_ResNet_V2

    『PyTorch × TensorFlow』第十七弹_ResNet快速实现 要点 神经网络逐层加深有Degradiation问题,准确率先上升到饱和,再加深会下降,这不是过拟合,是测试集和训练集同时下 ...

  8. intellij idea 编译 kafka 源码

    1. 从 GitHub 网站,git clone kafka 源码 2. 下载安装好 gradle,scala 3. 进入 kafka 项目目录,依次执行 gradle wrapper,gradle ...

  9. webstorm激活教程

    虽然webStorm,phpStorm以及jetbrains系列的很好用,但是每隔一段时间就需要激活一下,这样太费劲了,今天军哥给大家推荐一个永久激活的办法 此教程适用于jetbrains 的所有系列 ...

  10. SpringBoot使用CORS解决跨域请求问题

    什么是跨域? 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 如果一个请求地址里面的协议.域名和端口号都相同,就属于同源. ...