模板—插头dp(Ural 1519 Formula 1)
括号表示法:
据说比下一个要快而且灵活。
#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)的更多相关文章
- bzoj1814 Ural 1519 Formula 1(插头dp模板题)
1814: Ural 1519 Formula 1 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 924 Solved: 351[Submit][Sta ...
- 【BZOJ1814】Ural 1519 Formula 1 (插头dp)
[BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...
- 【BZOJ1814】Ural 1519 Formula 1 插头DP
[BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...
- 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 ...
- ural 1519 Formula 1(插头dp)
1519. Formula 1 @ Timus Online Judge 干了一天啊!!!插头DP入门. 代码如下: #include <cstdio> #include <cstr ...
- Ural 1519 Formula 1 插头DP
这是一道经典的插头DP单回路模板题. 用最小表示法来记录连通性,由于二进制的速度,考虑使用8进制. 1.当同时存在左.上插头的时候,需要判断两插头所在连通块是否相同,若相同,只能在最后一个非障碍点相连 ...
- URAL 1519 Formula 1(插头DP,入门题)
Description Background Regardless of the fact, that Vologda could not get rights to hold the Winter ...
- 插头DP讲解+[BZOJ1814]:Ural 1519 Formula 1(插头DP)
1.什么是插头$DP$? 插头$DP$是$CDQ$大佬在$2008$年的论文中提出的,是基于状压$D$P的一种更高级的$DP$多用于处理联通问题(路径问题,简单回路问题,多回路问题,广义回路问题,生成 ...
- HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...
- Ural 1519. Formula 1 优美的插头DP
今天早上学了插头DP的思想和最基础的应用,中午就开始敲了,岐哥说第一次写不要看别人代码,利用自己的理解一点点得写出来,这样才锻炼代码能力!于是下午慢慢地构思轮廓,一点点地敲出主体代码,其实是很磨蹭的, ...
随机推荐
- 使用junit单元测试,报Cannot instantiate test(s): java.lang.SecurityException: Prohibited package name: java.com.com.test
在测试类中不能一级包名不能以java开头, 将包改为com.com.test就好了.
- C++: Mac上安装Boost库并使用CLion开发
1.下载安装Boost库 官网下载最新版本1.65.0:http://www.boost.org/users/history/version_1_65_0.html 选择UNIX版本: 下载后解压cd ...
- 解决VC编译的DLL要安装对应运行环境否则无法使用的问题
编译时候改成静态链接,再通过使用Depends软件查看依赖即可.具体操作步骤:项目->属性->配置属性->C/C++-代码生成->运行库->多线程(/MT)说明:这种方法 ...
- LUOGU 2593 : [Zjoi2006] 超级麻将
传送门 解题思路 直接爆搜全T..状态数太多了,所以我们考虑贪心+剪枝.贪心:先拿三个连着的,再拿四个一样的,再拿三个一样的,最后拿两个一样的这样的搜索顺序最优,两个的放最后是因为只要这样的一个,三个 ...
- 图文结合深入理解 JS 中的 this 值
图文结合深入理解 JS 中的 this 值 在 JS 中最常见的莫过于函数了,在函数(方法)中 this 的出现频率特别高,那么 this 到底是什么呢,今天就和大家一起学习总结一下 JS 中的 th ...
- python csv文件打开错误:_csv.Error: line contains NULL byte
当python读取文件出现_csv.Error: line contains NULL byte时, # -*- coding:utf-8 -*- import csv with open(r'E:\ ...
- 使用帝国备份王软件提示 Parse error: syntax error, unexpected end of file
使用帝国备份王软件提示 Parse error: syntax error, unexpected end of file时, 可以尝试一下方法: 1.php.ini要把short_open_tag ...
- MSSQL → 01:SQLServer 2008概述及安装
据库的发展史 在人类诞生以来,就有记录数据的需求,在远古时代就有了结绳记事的故事,而随着科技的进步,我们记录数据的方式也发生了天翻地覆的变化,从效率低.规模小.不能适应信息高速发展的需要的手工或者简单 ...
- 仿Google Nexus菜单样式
在线演示 本地下载
- objectarx之模型空间
AcDbObjectId CCommonFuntion::PostToModelSpace(AcDbEntity* pEnt){ // 获得指向块表的指针 AcDbBlockTable *pBlock ...