直接看CDQ在2008年的论文吧.

个人认为她的论文有两个不明确的地方, 这里补充一下: 首先是轮廓的概念. 我们在进行插头DP时, 是从上往下, 从左往右逐个格子进行的, 已经处理的格子与未经处理的格子之间的分界线叫做轮廓线. 因此每个时刻轮廓线的长度都为列数加一. 每次处理下一个格子时, 有且仅有两条轮廓线会变动.

至于什么是插头, 这个很好理解, 就是从格子里面连出来的线就叫做插头. 不难看出, 在本题中, 一个不可选的格子没有插头; 一个可选的格子有且仅有两个插头. 穿过轮廓线的插头叫做轮廓线上的插头.

剩下的自己看即可.

考虑如何DP, 根据论文的描述, 我们发现轮廓线上的插头可以被看作是一个括号序列; 一个合法的状态要求轮廓线也是合法的. 同时为了限制只能存在一条路径, 我们需要在代码中加以体现.

#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std;
const int N = 15, M = 15, SZ = (int)3e5, STT = 1594323;
int n, m;
char s[N][M];
int pw[M], enc[STT], dec[SZ], tp; // 分别表示加密和解密
long long f[SZ], g[SZ];
inline int check(int stt)
{
int cnt = 0;
for(int i = 0; i < m + 1; ++ i)
{
if(stt / pw[i] % 3 == 1) ++ cnt; else if(stt / pw[i] % 3 == 2) -- cnt;
if(cnt < 0) return 0;
}
return ! cnt;
}
inline void initialize()
{
pw[0] = 1; for(int i = 1; i <= m + 1; ++ i) pw[i] = pw[i - 1] * 3;
tp = 0;
for(int i = 0; i < pw[m + 1]; ++ i) if(check(i)) enc[i] = tp, dec[tp ++] = i;
}
inline int get(int stt, int pos) {return stt / pw[pos] % 3;}
int main()
{ #ifndef ONLINE_JUDGE freopen("ural1519.in", "r", stdin);
freopen("ural1519.out", "w", stdout); #endif int lstX = -1, lstY = -1;
scanf("%d %d\n", &n, &m); for(int i = 0; i < n; ++ i) scanf("%s", s[i]);
for(int i = 0; i < n; ++ i) for(int j = 0; j < m; ++ j) if(s[i][j] == '.') lstX = i, lstY = j;
initialize();
memset(g, 0, sizeof(g)); g[enc[0]] = 1;
for(int i = 0; i < n; ++ i)
{
for(int j = 0; j < m; ++ j)
{
swap(f, g); memset(g, 0, sizeof(g));
if(s[i][j] == '*')
{
for(int k = 0; k < tp; ++ k) if(! get(dec[k], j) && ! get(dec[k], j + 1)) g[k] = f[k];
continue;
}
else for(int k = 0; k < tp; ++ k) if(f[k])
{
int x = get(dec[k], j), y = get(dec[k], j + 1);
if(! x && ! y) g[enc[dec[k] + pw[j] + pw[j + 1] * 2]] += f[k];
else if(! x ^ ! y)
{
g[k] += f[k];
g[enc[dec[k] + (y - x) * pw[j] + (x - y) * pw[j + 1]]] += f[k];
}
else if(x == 1 && y == 1)
{
int p = j + 1, cnt = 0;
for(; p <= m; ++ p)
{
if(get(dec[k], p) == 1) ++ cnt; else if(get(dec[k], p) == 2) -- cnt;
if(! cnt) break;
}
g[enc[dec[k] - pw[j] - pw[j + 1] - pw[p]]] += f[k];
}
else if(x == 2 && y == 2)
{
int p = j, cnt = 0;
for(; ~ p; -- p)
{
if(get(dec[k], p) == 2) ++ cnt; else if(get(dec[k], p) == 1) -- cnt;
if(! cnt) break;
}
g[enc[dec[k] - 2 * pw[j] - 2 * pw[j + 1] + pw[p]]] += f[k];
}
else if(x == 1 && y == 2 && i == lstX && j == lstY) g[enc[dec[k] - pw[j] - 2 * pw[j + 1]]] += f[k];
// 这里就是限制只能存在一条路径的关键
else if(x == 2 && y == 1) g[enc[dec[k] - 2 * pw[j] - pw[j + 1]]] += f[k];
}
}
swap(f, g); memset(g, 0, sizeof(g));
for(int j = 0; j < tp && dec[j] < pw[m]; ++ j) g[enc[dec[j] * 3]] += f[j];
}
printf("%lld\n", f[enc[0]]);
}

ural 1519 fomular 1 既插头DP学习笔记的更多相关文章

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

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

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

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

  3. ural 1519 Formula 1(插头dp)

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

  4. bzoj1814 Ural 1519 Formula 1(插头DP)

    对插头DP的理解还不是很透彻. 先说一下肤浅的理解吧. 插头DP使用范围:指数级复杂度,且适用于解决网格图连通性问题,如哈密顿回路等问题.插头一般指每相邻2个网格的接口. 题目难度:一般不可做. 使用 ...

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

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

  6. URAL 1519 Formula 1 (插头DP,常规)

    题意:给一个n*m的矩阵,格子中是'*'则是障碍格子,不允许进入,其他格子都是必走的格子,所走格子形成一条哈密顿回路,问有多少种走法? 思路: 本来是很基础的题,顿时不知道进入了哪个坑.这篇插头DP的 ...

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

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

  8. 插头DP学习笔记——从入门到……????

    我们今天来学习插头DP??? BZOJ 2595:[Wc2008]游览计划 Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该 ...

  9. 插头DP学习笔记

    插头DP(我也不知道该怎么定义...)是一种类似于洛谷题目([模板]插头DP)的题目 题目特征为: 在棋盘上 某一维的数据范围很小 完全铺满 计数问题 直接看题吧. [模板]插头DP 给出n*m的方格 ...

随机推荐

  1. centos使用--vsftpd配置

    目录 1 在服务器配置FTP服务 1.1 在root权限下,通过如下命令安装Vsftp(以CentOS系统为例): 1.2 在启动vsftpd服务之前,需要登录云服务器修改配置文件,禁用匿名登录. 1 ...

  2. Install ADDS on Windows Server 2012 R2 with PowerShell

    Install ADDS on Windows Server 2012 R2 with PowerShell Posted by ethernuno on 20/04/2014 In this tut ...

  3. IOS开发---菜鸟学习之路--(十八)-利用代理实现向上一级页面传递数据

    其实我一开始是想实现微信的修改个人信息那样的效果 就是点击昵称,然后跳转到另外一个页面输入信息 但是细想发现微信的话应该是修改完一个信息后就保存了 而我做的项目可能需要输入多个数据之后再点击提交的. ...

  4. 55、android app借助友盟实现微信授权登录

    一.去微信开放平台的管理中心申请移动设备的审核(需进行开发者资质认证,每年300元) 1.获取应用的签名 2.在微信开放平台申请移动应用 两个注意点:①签名要填对 ②应用的包名要写对(tips: co ...

  5. 用python批量下载贴吧图片 附源代码

    环境:windows 7 64位:python2.7:IDE pycharm2016.1 功能: 批量下载百度贴吧某吧某页的所有帖子中的所有图片 使用方法: 1.安装python2.7,安装re模块, ...

  6. manjaro安装anaconda出错

    出错信息: ==> Creating package "anaconda"...  -> Generating .PKGINFO file...  -> Gene ...

  7. PAT——乙级1016

    乙级PAT的1016 乙级的题相对比较简单,我也是主要联系写代码的格式,而不是联系算法. 1016 部分A+B (15 point(s)) 正整数 A 的“D​A​​(为 1 位整数)部分”定义为由  ...

  8. A.Equals(B)和A==B的区别

    Equals 和 == 都是用于比较. 如果a和b都是值类型,则a.Equals(b) 和 a == b 结果相同,但是在引用类型是它们的行为是不同的: string a = new string(n ...

  9. [canvas入坑3] 类似ps中魔术棒或者画图中油漆桶的功能

    查看效果请到 http://philippica.github.io/  点击fill 这功能其实实现很low,最早高一看黑书的时候看到了floodfill算法感觉好神奇,转念一想这不就是bfs么!! ...

  10. bzoj3680吊打GTY

    题意:http://www.lydsy.com/JudgeOnline/problem.php?id=3680 sol  :吊打出题人(逃~ puts("nan") 出题人题解:h ...