题目: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. word->excel数据处理

    朋友发来一个word文件,里面的数据没有分割,想分割后放到excel统计 通常遇到这种数据,首先想到每一列数据有没有什么特征 类似这种数据,一种办法是按位数截取,mid函数,或者按第一次出现数字的方式 ...

  2. 【文献08】多移动机器人轨迹跟踪控制系统设计与实现-运动学ADRC控制

    参考: 陈俊, 俞立, 滕游. 多移动机器人轨迹跟踪控制系统设计与实现[J]. 计算机测量与控制, 2017(7). https://drive.wps.cn/view/p/28819052019?f ...

  3. Thread的中断机制(interrupt)

    先看收集了别人的文章,全面的了解下java的中断: 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的 ...

  4. QChartView绘制饼状图

    效果图: #include "mainwindow.h" #include "form.h" #include <QApplication> #in ...

  5. 如何解决ORA-28002 the password will expire within 7 days问题(密码快过期)

    1.问题描述: 今天登陆pl/sql工具时,提示 ORA-28002 the password will expire within 7 days 2.问题原因: oracle11g中默认在defau ...

  6. mac 配置php+php_fpm+nginx

    首先brew安装前面文章上有的 安装nginx  brew install nginx #启动nginx sudo nginx #测试配置是否有语法错误 sudo nginx -t 测试成功 如果不加 ...

  7. python 在.py文件中调用其他.py内的函数

      假设名为A.py的文件需要调用B.py文件内的C(x,y)函数 假如在同一目录下,则只需 import B if __name__ == "__main__": B.C(x,y ...

  8. python全栈开发笔记---------数据类型-----字典dict

    字典 #dict #1.基本结构 info= { "k1" : "v1", #键值对 "k2" : "v2" } ### ...

  9. TensorFlow函数:tf.random_shuffle

    tf.random_shuffle 函数 random_shuffle( value, seed=None, name=None ) 定义在:tensorflow/python/ops/random_ ...

  10. 运维grep语法

    grep的语法和用法 grep命令的格式: grep   [options]   PATTERN  [FILE] 其中:1,pattern是用正则表达式书写的模式.2,FILE是要查找的文件,可以是用 ...