括号表示法:

据说比下一个要快而且灵活。

 #include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define MAXN 20000
#define HASH 23333
#define ma(x,y) memset(x,y,sizeof(x))
using namespace std;
struct Hash_map
{
int size,first[HASH],next[MAXN];
#define f(x) first[x]
#define n(x) next[x]
LL sta[MAXN],sum[MAXN];
void init(){size=;ma(first,-);ma(sum,);}
void push(LL states,LL Sum)
{
int pos=(states%HASH+HASH)%HASH;
for(int i=f(pos);i>=;i=n(i))
if(sta[i]==states){sum[i]+=Sum;return;}
sta[size]=states;
sum[size]=Sum;
n(size)=f(pos);f(pos)=size++;
}
}dp[];
int n,m,map[][],bin[],fx,fy;//最后一个可行点坐标
int now,pre;
int mov[]={,,,,,,,,,,,,};
inline int getbit(LL st,int k){return (st>>mov[k])&;}//第k位状态
inline int pybit(LL st,int k){return st<<mov[k];}//平移k位
inline LL clrbit(LL st,int i,int j){return st&(~(<<mov[i]))&(~(<<mov[j]));}//清空i,j位
inline int fl(LL st,int pos)//从左往右找和当前pos位置匹配的右括号
{
int cnt=;
for(int i=pos+;i<=m;i++)
{
int k=getbit(st,i);
if(k==)cnt++;
else if(k==)cnt--;
if(!cnt)return i;
}
}
inline int fr(LL st,int pos)//从右往左找和当前pos位置匹配的左括号
{
int cnt=;
for(int i=pos-;i>=;i--)
{
int k=getbit(st,i);
if(k==)cnt--;
else if(k==)cnt++;
if(!cnt)return i;
}
}
void DP(int x,int y,int k)
{
int l=getbit(dp[pre].sta[k],y-);
int up=getbit(dp[pre].sta[k],y);
LL st=clrbit(dp[pre].sta[k],y-,y);
LL v=dp[pre].sum[k];
if(!l&&!up)
{
if(!map[x][y]){dp[now].push(st,v);return;}
if(x<n&&y<m&&map[x+][y]&&map[x][y+])
dp[now].push(st|pybit(,y-)|pybit(,y),v);
}
else if(!l||!up)
{
int e=l+up;
if(x<n&&map[x+][y])
dp[now].push(st|pybit(e,y-),v);
if(y<m&&map[x][y+])
dp[now].push(st|pybit(e,y),v);
}
else if(l==&&up==)
dp[now].push(st^pybit(,fl(st,y)),v);
else if(l==&&up==)
dp[now].push(st^pybit(,fr(st,y-)),v);
else if(l==&&up==)
dp[now].push(st,v);
else if(x==fx&&y==fy)
dp[now].push(st,v);
}
LL solve()
{
dp[].init();
dp[].push(,);
now=,pre=;
for(int i=;i<=n;i++)
{
pre=now,now^=;dp[now].init();
for(int k=;k<dp[pre].size;k++)
dp[now].push(pybit(dp[pre].sta[k],),dp[pre].sum[k]);
for(int j=;j<=m;j++)
{
pre=now,now^=;dp[now].init();
for(int k=;k<dp[pre].size;k++)
DP(i,j,k);
}
}
for(int i=;i<dp[now].size;i++)
if(dp[now].sta[i]==)
return dp[now].sum[i];
return ;
}
signed main()
{
// freopen("in.txt","r",stdin); bin[]=;for(int i=;i<=;i++)bin[i]=bin[i-]*;
cin>>n>>m;char t;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
cin>>t;
if(t=='*')map[i][j]=;
else map[i][j]=;
}
fx=;
for(int i=n;i>&&!fx;i--)
for(int j=m;j>&&!fx;j--)
if(map[i][j])
fx=i,fy=j;
if(fx==)puts("");
else cout<<solve()<<endl;
}

括号表示法(这个是自己写的)

最小表示法(看不懂,下面是标程):

不过连我都能看出来它慢那它就是真的慢了。而且我也并没有觉得它好理解……

找到一个和自己码风相似的不容易啊……

 #include<bits/stdc++.h>

 #define LL long long
using namespace std;
const int maxn=,inc=,bit=;//3位二进制以及111的表示
int n,m,now,pre,code[],bin[],res[];//用来表示状态的每一位的数值
char gp[][],fx,fy;//图和最后的可行点
struct node//离散化hash
{
int head[maxn],next[maxn],size;
LL sum[maxn],sta[maxn];
void clear()
{
memset(head,-,sizeof(head));
size=;
}
void push(LL st,const LL v)
{
LL hash=st%maxn;
for(int i=head[hash];i>=;i=next[i])
{
if(sta[i]==st)
{
sum[i]+=v;
return ;
}
}
sta[size]=st,sum[size]=v;
next[size]=head[hash],head[hash]=size++;
}
}dp[];
inline LL encode(int m)//将code转换成状态
{
LL st=;
int cnt=;
memset(bin,-,sizeof(bin));
bin[]=;
for(int i=m;i>=;i--)
{
if(bin[code[i]]==-)
bin[code[i]]=cnt++;
code[i]=bin[code[i]];
st<<=inc;
st|=code[i];
}
return st;
}
inline void decode(LL st,int m)//将状态转换成code
{
for(int i=;i<=m;i++)
{
code[i]=st&bit;
st>>=inc;
}
}
void DP(int x,int y,int k)//dp具体情况具体分析
{
decode(dp[pre].sta[k],m);
int l=code[y-];
int up=code[y];
code[y-]=code[y]=;
memcpy(res,code,sizeof(code));
LL v=dp[pre].sum[k];
if(!l&&!up)
{
if(gp[x][y]=='*')
dp[now].push(encode(m),v);
else if(x<n&&y<m&&gp[x+][y]=='.'&&gp[x][y+]=='.')
{
code[y]=code[y-]=bit;
dp[now].push(encode(m),v);
}
}
else if(!l||!up)
{
int e=l+up;
if(x<n&&gp[x+][y]=='.')
{
code[y-]=e;
dp[now].push(encode(m),v);
memcpy(code,res,sizeof(res));
}
if(y<m&&gp[x][y+]=='.')
{
code[y]=e;
dp[now].push(encode(m),v);
}
}
else if(l!=up)
{
for(int i=;i<=m;i++)
if(code[i]==up)
code[i]=l;
dp[now].push(encode(m),v);
}
else if(x==fx&&y==fy)
dp[now].push(encode(m),v);
}
LL solve()
{
dp[].clear();//初始化状态
dp[].push(,);
now=,pre=;
for(int i=;i<=n;i++)//逐格逐状态枚举转移
{
pre=now,now^=,dp[now].clear();
for(int k=;k<dp[pre].size;k++)//轮廓线行转移
dp[now].push(dp[pre].sta[k]<<inc,dp[pre].sum[k]);
for(int j=;j<=m;j++)
{
pre=now,now^=,dp[now].clear();
for(int k=;k<dp[pre].size;k++)
{
DP(i,j,k);
}
}
}
for(int i=;i<dp[now].size;i++)
if(dp[now].sta[i]==)
return dp[now].sum[i];
return ;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=;i<=n;i++)//都是从1开始
scanf("%s",&gp[i][]);
fx=fy=;
for(int i=n;i>&&!fx;i--)//寻找最终的位置
for(int j=m;j>&!fx;j--)
if(gp[i][j]=='.')
fx=i,fy=j;
if(fx==)puts("");
else cout<<solve()<<endl;
}
}

最小表示法(摘自某大佬)

模板—插头dp(Ural 1519 Formula 1)的更多相关文章

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

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

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

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

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

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

  4. 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 ...

  5. ural 1519 Formula 1(插头dp)

    1519. Formula 1 @ Timus Online Judge 干了一天啊!!!插头DP入门. 代码如下: #include <cstdio> #include <cstr ...

  6. Ural 1519 Formula 1 插头DP

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

  7. URAL 1519 Formula 1(插头DP,入门题)

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

  8. 插头DP讲解+[BZOJ1814]:Ural 1519 Formula 1(插头DP)

    1.什么是插头$DP$? 插头$DP$是$CDQ$大佬在$2008$年的论文中提出的,是基于状压$D$P的一种更高级的$DP$多用于处理联通问题(路径问题,简单回路问题,多回路问题,广义回路问题,生成 ...

  9. HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...

  10. Ural 1519. Formula 1 优美的插头DP

    今天早上学了插头DP的思想和最基础的应用,中午就开始敲了,岐哥说第一次写不要看别人代码,利用自己的理解一点点得写出来,这样才锻炼代码能力!于是下午慢慢地构思轮廓,一点点地敲出主体代码,其实是很磨蹭的, ...

随机推荐

  1. Python 爬取高清桌面壁纸

    今天写了一个脚本用来爬取ZOL桌面壁纸网站的高清图片: 链接:http://desk.zol.com.cn/1920x1080/ 本程序只爬了美女板块的图片,若要下载其他板块,只需修改程序中的&quo ...

  2. MyBatis小问题-Mapper中错误No constructor found...

    前两天又被公司叫去修改其他产品的一些问题了,没有看java相关的,今天周六,看了看MyBatis东西. 就是简单的在MySql中建了个users表,很简单,包含id,name,age,写了个bean. ...

  3. npm ci命令比npm installer命令快2至10倍

    npm 5.7.1的发布给我们带了一系列新的功能. 其中我最喜欢的就是npm ci命令了. npm ci命令 1.npm ci命令只根据lock-file去下载node_modules. 如果你的pa ...

  4. scala的插值器

    Scala 为我们提供了三种字符串插值的方式,分别是 s, f 和 raw.它们都是定义在 StringContext 中的方法. s 字符串插值器 val a = 2println(s"小 ...

  5. Windows Phpstrom svn 配置

    网上百度找到的解决方案行不通,就是下图两项都不选中.临时是可以的,但是到了第二天,又不行了. 以下是自己瞎弄的,居然可以了. 第一步:安装TortoiseSVN 1.8.* ,注意安装选项要选上com ...

  6. vue使用填坑之:model和v-model的区别

    v-model通常用于input的双向数据绑定 <input v-model="parentMsg">,也可以实现子组件到父组件数据的双向数据绑定:首先说说v-mode ...

  7. webpack学习之—— 模块热替换(Hot Module Replacement)

    模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换.添加或删除模块,而无需重新加载整个页面.主要是通过以下几种方式,来显著加快开发速度: 保留在完全重 ...

  8. CF981H K Paths

    CF981H K Paths 题解 一道不错的分治ntt题目 题目稍微转化一下,就是所有k条链的存在交,并且交的部分都被覆盖k次 所以一定是两个点,之间路径选择k次,然后端点两开花 f[x]表示x子树 ...

  9. C#中抽象方法与虚方法的区别(转)

    C#中抽象方法与虚方法的区别   一.抽象方法:只在抽象类中定义,方法修饰符不能使用private,virtual,static. 抽象方法如下示: public abstract class Peo ...

  10. php语言的核心知识点

    PHP:脚本语言,网站建设,服务器端运行PHP定义:一种服务器端的 HTML 脚本/编程语言,是一种简单的.面向对象的.解释型的.健壮的.安全的.性能非常之高的.独立于架构的.可移植的.动态的脚本语言 ...