【模板】插头dp
题解:
插头$dp$中经典的回路问题。
首先了解一下插头。
一个格子,上下左右四条边对应四个插头。就像这样:
四个插头。
一个完整的哈密顿回路,经过的格子一定用且仅用了两个插头。
所以所有被回路经过的格子有六种状态,即左上,左右,左下,上右,上下,右下。
这几个就是插头$dp$的基本。
然后我们来了解一下轮廓线。
红线就叫轮廓线。
我们可以利用轮廓线作为状态dp,将轮廓线一点点右推+下推,直到推完,这样我们就可以得出全局答案啦!!!
但是怎么转移……
插头!
我们可以稍微讨论一下,讨论拐角处的插头状态,然后转移就好了。
听起来很简单恶心。
实际上很简单恶心。
现在我们突然想到一个问题,就是状态怎么记录。
主要有两种方法,一种叫最小表示法(不是字符串的最小表示法),一种叫括号序列。
最小表示法,是将互相联通的插头归入一类。如果我们将其采用字典序最小的方法表示,那么对于某条轮廓线表示法与轮廓线状态一一对应。
括号表示法,是由于网格中两条哈密顿回路路径不可相交的性质。
如果我们认为回路有方向,比如轮廓线左面的为进,右面的为出,那我们可以将进看作‘(’,将出看作‘)’。
由于上面那条性质,我们可以知道一个括号序列对应一种轮廓线状态。
而且括号表示法比最小表示法好写。
括号表示法怎么用?
三进制。0表示'-',1表示'(',2表示')'。
压成一个数字然后用挂链存起来就好了。
(我用的括号表示法)
现在我们就差转移了。
(其实我非常不愿意在博客里写但是良心的我还是写了)
状态1:)(
直接用下面这个接上即可。
而且刚好满足括号匹配。
状态2:(-或)-
两种情况。
或
状态3:-)或-(
还是两种情况。
或
状态4:))或((
这个我们还是要放状态1的那个块。
但是不满足括号匹配怎么办?
向左/向右找一个换上。
举个例子,比如说原序列是:(()(()))()(),
然后中间两个接在一起,序列就应该成为:(()()--)()()
注意那个变号。
状态5:--
直接放插头。
状态6:()
一旦合并说明括号序列清空。
所以只能在最后一格合并状态6。
所以我们要知道最后一格在哪。
没有状态7。
上述状态都是在当前格子可填且插头指向格子可填时可选。
然后上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 15
#define ll long long
#define M 100000
int n,m;
ll bas[N];
char ch[N][N];
struct Map
{
int hed[M+],cnt[];
struct EG
{
int nxt;ll to,w;
}e[<<][];
void ae(int f,ll t,ll w,int k)
{
e[++cnt[k]][k].to = t;
e[cnt[k]][k].nxt = hed[f];
e[cnt[k]][k].w = w;
hed[f] = cnt[k];
}
void push(ll u,ll d,int k)
{
int f = (int)(u%M);
for(int j=hed[f];j;j=e[j][k].nxt)
if(e[j][k].to==u)
{
e[j][k].w+=d;
return ;
}
ae(u%M,u,d,k);
}
void clear(int k)
{
memset(hed,,sizeof(hed));
cnt[k] = ;
}
}mp;
ll ans;int tx,ty;
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",ch[i]+);
for(int j=;j<=m;j++)
if(ch[i][j]=='.')
tx=i,ty=j;
}
bas[] = ;
for(int i=;i<=m+;i++)bas[i]=bas[i-]<<;
mp.push(,,);
for(int k=,i=;i<=n;i++)
{
for(int j=;j<=mp.cnt[k];j++)mp.e[j][k].to<<=;
for(int j=;j<=m;j++)
{
k^=;mp.clear(k);
for(int o=;o<=mp.cnt[!k];o++)
{
ll now = mp.e[o][!k].to,val = mp.e[o][!k].w;
int lp = (now>>(j-)*)&,rp = (now>>j*)&;
if(ch[i][j]=='*')
{
if(!lp&&!rp)
{
mp.push(now,val,k);
}
}else
{
if(!lp&&!rp)
{
if(ch[i+][j]=='.'&&ch[i][j+]=='.')
{
ll tmp = now+bas[j-]+bas[j]*;
mp.push(tmp,val,k);
}
}else if(!lp&&rp)
{
if(ch[i+][j]=='.')
{
ll tmp = now+bas[j-]*rp-bas[j]*rp;
mp.push(tmp,val,k);
}
if(ch[i][j+]=='.')
{
ll tmp = now;
mp.push(tmp,val,k);
}
}else if(lp&&!rp)
{
if(ch[i+][j]=='.')
{
ll tmp = now;
mp.push(tmp,val,k);
}
if(ch[i][j+]=='.')
{
ll tmp = now-bas[j-]*lp+bas[j]*lp;
mp.push(tmp,val,k);
}
}else
{
if(lp==&&rp==)
{
ll tmp = now-bas[j-]-bas[j];
int sum = ;
for(int j0=j+;j0<=m+;j0++)
{
if(((now>>(j0-)*)&)==)sum++;
if(((now>>(j0-)*)&)==)sum--;
if(!sum)
{
mp.push(tmp-bas[j0-],val,k);
break;
}
}
}else if(lp==&&rp==)
{
ll tmp = now-bas[j-]*-bas[j]*;
int sum = ;
for(int j0=j-;j0>=;j0--)
{
if(((now>>(j0-)*)&)==)sum--;
if(((now>>(j0-)*)&)==)sum++;
if(!sum)
{
mp.push(tmp+bas[j0-],val,k);
break;
}
}
}else
{
if(lp==&&rp==)
{
ll tmp = now-bas[j-]*-bas[j];
mp.push(tmp,val,k);
}else if(i==tx&&j==ty)ans+=val;
}
}
}
}
}
}
printf("%lld\n",ans);
return ;
}
【模板】插头dp的更多相关文章
- 模板—插头dp(Ural 1519 Formula 1)
括号表示法: 据说比下一个要快而且灵活. #include<iostream> #include<cstring> #include<cstdio> #define ...
- 插头DP模板
/* 插头dp模板 抄的GNAQ 的 括号表示法 */ #include<cstdio> #include<algorithm> #include<cstring> ...
- 模板:插头dp
前言: 严格来讲有关dp的都不应该叫做模板,因为dp太活了,但是一是为了整理插头dp的知识,二是插头dp有良好的套路性,所以姑且还叫做模板吧. 这里先推荐一波CDQ的论文和这篇博客http://www ...
- bzoj1814 Ural 1519 Formula 1(插头dp模板题)
1814: Ural 1519 Formula 1 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 924 Solved: 351[Submit][Sta ...
- LG5056 【模板】插头dp
题意 题目背景 ural 1519 陈丹琦<基于连通性状态压缩的动态规划问题>中的例题 题目描述 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? 输 ...
- P5056 【模板】插头dp
\(\color{#0066ff}{ 题目描述 }\) 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? \(\color{#0066ff}{输入格式}\) 第1 ...
- 插头dp
插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...
- hdu1964之插头DP求最优值
Pipes Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
- 插头dp初探
问题描述 插头dp用于解决一类可基于图连通性递推的问题.用插头来表示轮廓线上的连通性,然后根据连通性与下一位结合讨论进行转移. 表示连通性的方法 与字符串循环最小表示不同,这种方法用于给轮廓线上的联通 ...
随机推荐
- kettle系列-我的开源kettle调度、管理平台[kettle-manager]介绍
kettle管理工具 专门为kettle这款优秀的ETL工具开发的web端调度.管理工具. 新版本 项目简介 kettle作为非常优秀的开源ETL工具得到了非常广泛的使用,一般的使用的都是使用客户端操 ...
- Codeforces732F Tourist Reform
求出无向图的所有边双联通分量,然后缩点就成了一颗树. 然后我们选取最大的那个边双联通分量作为根,这样我们就可以确定所有割边的方向了. 对于边双联通分量里面的边,我们随便dfs一下就可以把它变成强连通分 ...
- 纯javaScript实现元素平滑滚动,改进前两个版本,支持鼠标滚轮滚动和点击元素滚动,滚动更顺畅
windowScroll(id, number, distance, direction, obj) 参数介绍: 1.id:所要滚动的元素id; 2.number:滚动次数; 3.distance:每 ...
- 关于margin和padding取值为百分比和负值的总结
以下是自己学习过程中的总结,直接上结论: 1.margin/padding取值为百分比: margin和padding四个方向上的取值为百分比都是参照父级元素的宽度来计算的. 2.margin取值为负 ...
- [问题][已解决] 并发场景下 "mysql: too many connections" 原因
问题出现是这样的,用node写爬虫, 之前每条数据都是await插入,并且是阻塞的,后来改成了非阻塞,可以并行插入操作,结果一直找不到原因. 后来在日志中找到了 too many connection ...
- SQL-添加字段处理
1.alter table [dbo].[SiteTracks] drop constraint DF__SiteTrack__Audit__47DBAE452.ALTER TAB ...
- Mike and gcd problem CodeForces - 798C
题目 (智商题 or 糟心的贪心) 题意: 有一个数列a1,a2,...,an,每次操作可以将相邻的两个数x,y变为x-y,x+y,求最少的操作数使得gcd(a1,a2,...,an)>1.gc ...
- 18.3.2从Class上获取信息(方法)
package d18_3_1; import java.lang.reflect.Method; import java.util.Arrays; /** * 获取Class对应类所包含的方法的四个 ...
- 137 Single Number II 数组中除了一个数外,其他的数都出现了三次,找出这个只出现一次的数
给定一个整型数组,除了一个元素只出现一次外,其余每个元素都出现了三次.求出那个只出现一次的数.注意:你的算法应该具有线性的时间复杂度.你能否不使用额外的内存来实现?详见:https://leetcod ...
- solr的多条件组合查询和solr的范围查询【转】
solr的多条件组合查询和solr的范围查询 版权声明:本文为博主原创文章,供大家参考,但不要抄袭哦! 存在问题:为了减轻数据库的访问压力,往往我们将必要的数据存储到solr中,并给部分字段建立索引, ...