题面:

传送门

思路:

插头dp基础教程

先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走

看到这个数据范围,还有回路处理,就想到使用插头dp来做了

观察一下发现,这道题因为都是回路,所以联通块上方的插头一定两两配对,可以使用括号序列代替最小表示法

分情况讨论一下

情况一:当前格子上方和左方都没有插头

这种时候可以继续,也可以给当前格子加一个下插头一个右插头,相当于一个新的联通分量

情况二:上方有一个下插头,左边没有

这时有两个决策:可以向右转,也可以继续向下,操作就是分别给这个格子一个右插头或者一个下插头

注意此时新插头的括号类型和原来的那个插头相同(画个图可以理解一下)

情况三:左边有一个右插头,上面没有

同情况二,转弯或者直走

情况四:都有插头,而且两个插头是同一括号

这种情况,我们可以将这两个插头合并,在当前格子把这条路径封闭了

但是这里需要考虑一下其他的插头

我们去掉了两个相同的括号,就需要把另外一个括号反过来配对才行

比如当前的括号序列是 ((##()#())##),加粗的是我们要合并的两个括号,那么这两个)变成#以后,它们原来匹配的左括号(就失配了,需要其中一个(右边的那个)左括号变成右括号,两个重新配对

也就是((##()#())##)变成((##()#(####)变成((##()#)####)

当然也可以画个图理解一下,两条路径相当于是绕了圈接起来了

这个操作需要扫一遍整个序列,是$O\left(n\right)$的,当然也可以预处理变成$O\left(1\right)$

情况五:都有插头,且两个是)(

这时候直接合并就好了,图片同上(理解一下,博主懒得再画一个图了.......)

情况六:都有插头,而且两个是()

这种时候只有在最后一个非障碍格子才能合并,标志着路径完全封闭,得到了一个答案

图中的蓝色和绿色代表样例中的两条路径,再最后一个格子合并

状态数略多,可以滚动数组+哈希处理

分类讨论的时候注意可不可以这么做(需要判断下一个格子是否为障碍)

Code:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define hash ddf
using namespace std;
int n,m,x[][],cur,pre,ex,ey;
int st[][];ll ans[][],re;
int tot[],bit[],state[],st_tot,hash=;
struct edge{
int to,next;
}a[];
void insert(int sta,ll val){
// cout<<"insert "<<sta<<ends<<val<<endl;
int p=sta%hash,i;
for(i=state[p];i;i=a[i].next){
if(st[cur][a[i].to]==sta){
ans[cur][a[i].to]+=val;return;
}
}
tot[cur]++;
a[++st_tot].to=tot[cur];
a[st_tot].next=state[p];
state[p]=st_tot;st[cur][tot[cur]]=sta;ans[cur][tot[cur]]=val;
}
int main(){
int i,j,k,l,now,down,right;ll val;char s[];
scanf("%d%d",&n,&m);
for(i=;i<=n;i++){
scanf("%s",s);
for(j=;j<m;j++)
if(s[j]=='.')
x[i][j+]=,ex=i,ey=j+;
}
for(i=;i<;i++) bit[i]=i<<;
cur=;tot[cur]=;ans[cur][]=;st[cur][]=;
for(i=;i<=n;i++){
for(j=;j<=tot[cur];j++) st[cur][j]<<=;
for(j=;j<=m;j++){
// cout<<"begin "<<i<<ends<<j<<endl;
st_tot=;memset(state,,sizeof(state));
pre=cur;cur^=;tot[cur]=;
for(k=;k<=tot[pre];k++){
now=st[pre][k];val=ans[pre][k];
down=(now>>bit[j-])%;right=(now>>bit[j])%;
// cout<<" from "<<now<<ends<<val<<ends<<down<<ends<<right<<endl;
if(!x[i][j]){
if(!down&&!right){
insert(now,val);continue;
}
}
else if(!down&&!right){
if(x[i][j+]&&x[i+][j])
insert(now+(<<bit[j-])+((<<bit[j])<<),val);
}
else if(!down&&right){
if(x[i][j+]) insert(now,val);
if(x[i+][j])
insert(now-right*(<<bit[j])+right*(<<bit[j-]),val);
}
else if(down&&!right){
if(x[i+][j]) insert(now,val);
if(x[i][j+])
insert(now+down*(<<bit[j])-down*(<<bit[j-]),val);
}
else if(down==&&right==){
int cnt=;
for(l=j+;l<=m;l++){
if((now>>bit[l])%==) cnt++;
if((now>>bit[l])%==) cnt--;
if(!cnt){
insert(now-(<<bit[l])-(<<bit[j])-(<<bit[j-]),val);
break;
}
}
}
else if(down==&&right==){
int cnt=;
for(l=j-;l>=;l--){
if((now>>bit[l])%==) cnt++;
if((now>>bit[l])%==) cnt--;
if(!cnt){
insert(now+(<<bit[l])-((<<bit[j])<<)-((<<bit[j-])<<),val);
break;
}
}
}
else if(down==&&right==){
insert(now-((<<bit[j-])<<)-(<<bit[j]),val);
}
else if(down==&&right==){
if(i==ex&&j==ey) re+=val;
}
}
}
}
printf("%lld\n",re);
}

[URAL1519] Formula 1 [插头dp入门]的更多相关文章

  1. URAL1519 Formula 1 —— 插头DP

    题目链接:https://vjudge.net/problem/URAL-1519 1519. Formula 1 Time limit: 1.0 secondMemory limit: 64 MB ...

  2. URAL Formula 1 ——插头DP

    [题目分析] 一直听说这是插头DP入门题目. 难到爆炸. 写了2h,各种大常数,ural垫底. [代码] #include <cstdio> #include <cstring> ...

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

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

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

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

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

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

  6. hdu 1693 插头dp入门

    hdu1693 Eat the Trees 题意 在\(n*m\)的矩阵中,有些格子有树,没有树的格子不能到达,找一条或多条回路,吃完所有的树,求有多少种方法. 解法 这是一道插头dp的入门题,只需要 ...

  7. 动态规划之插头DP入门

    基于联通性的状态压缩动态规划是一类非常典型的状态压缩动态规划问题,由于其压缩的本质并不像是普通的状态压缩动态规划那样用0或者1来表示未使用.使用两种状态,而是使用数字来表示类似插头的状态,因此.它又被 ...

  8. bzoj 1814 Ural 1519 Formula 1 ——插头DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1814 普通的插头 DP .但是调了很久.注意如果合并两个 1 的话,不是 “把向右第一个 2 ...

  9. Ural 1519 Formula 1 插头DP

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

随机推荐

  1. Linux一键脚本合集vps

    首先,想说说一键脚本流行的原因何在? 众所周知的是,Linux 是占据大半壁江山的服务器系统,但在桌面上的占有率可就远不是那么回事儿了,使用和熟悉 Linux 的人远没有 Windows 多,但又因为 ...

  2. 从用户访问网站流程开始,细说web网络基础

    1.用户访问网站流程框架 2.dns解析原理 3.tcp/ip三次握手过程原理,11种连接状态 4.tcp/ip四次挥手过程原理,11种连接状态 5.http协议原理(www服务的请求过程)请求细节, ...

  3. python_78_软件目录结构规范

    一定要看http://www.cnblogs.com/alex3714/articles/5765046.html #print(__file__)#打印的是文件的相对路径 import os pri ...

  4. python_52_函数返回值2

    def test1(x,y): print(x,y) test1(1,2)#位置参数调用,按顺序来,与形参一一对应 test1(y=1,x=2)#输出为2 1,不是1 2.关键字参数调用按关键字,不按 ...

  5. Windows环境下在Oracle VM VirtualBOX下克隆虚拟机镜像(克隆和导入)

    Windows环境下在Oracle VM VirtualBOX下克隆虚拟机镜像: 注:直接复制一个.vdi 虚拟硬盘再挂上去就可以,但Virtualbox居然提示UUID重复,无法使用. 则,可以通过 ...

  6. java基础——线程池

    第2章 线程池 2.1 线程池概念 线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源. 我们详细的解释一下为什么要使用线程池 ...

  7. ASP.NET补充

    字典类的子集 using System.Collections.Generic; Dictionary<string, string> dicB = new Dictionary<s ...

  8. 移动端rem匹配

    Rem是相对于根元素font-size大小的单位 记inphone5屏幕宽度是 320px font-size16px 1rem=16px <html>   <head>    ...

  9. 网络流_Edmond-Karp算法、Dinic算法

    转载:网络流基础篇——Edmond-Karp算法             BY纳米黑客 网络流的相关定义: 源点:有n个点,有m条有向边,有一个点很特殊,只出不进,叫做源点. 汇点:另一个点也很特殊, ...

  10. 读取properties的简单方法,使用@Configuration

    配置类代码如下 import org.springframework.beans.factory.annotation.Value; import org.springframework.contex ...