直接看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. HDU 3368 Reversi

    http://acm.hdu.edu.cn/showproblem.php?pid=3368 题意:模拟黑白棋,下一步黑手最大可以转化多少个白旗 分析:暴力 原先的思路是找到D然后遍历其八个方向,直到 ...

  2. 等比例适配所有屏幕---css3 rem用法

    1,rem的定义 rem(font size of the root element)是指相对于根元素的字体大小的单位.rem是一个相对单位.和em非常相似.em(font size of the e ...

  3. log4j2用Log4jContextSelector启动参数配置全局异步日志是如何使用disruptor

    与 log4j2用asyncRoot配置异步日志是如何使用disruptor差异有几个: 给disruptor实例的EventFactory不同 此处EventFactory采用的是RingBuffe ...

  4. ArrayList以及Map小练

    ArrayList常用方法 public static void main(String[] args) { List list = new ArrayList(); List list1 = new ...

  5. STW 团队项目分析

    序言 经过我们团队的详细讨论,最终确定我们的项目立意,它包含这我们每个人的观点,我相信我们可以做的很好,Believe......................................... ...

  6. 【转】UGUI EventSystem

    EventSystem   The EventSystem is a way of sending events to objects in the application based on inpu ...

  7. 只显示前几条数据的sql语句写法 七种数据库中Select Top的使用方法

    七种数据库中Select Top的使用方法 1. Oracle数据库 SELECT * FROM TABLENAME WHERE ROWNUM <= N 2. Infomix数据库 SELECT ...

  8. Android EditText默认不弹出输入法,以及获取光标,修改输入法Enter键的方法

    一.Android EditText默认不弹出输入法的办法:1. 在AndroidManifest.xml中将需要默认隐藏键盘的Activity中添加属性即可(常用此方法) android:windo ...

  9. pc端自适应方案

    一.常见处理方式 定宽 电商类.内容为主的网站几乎采用这种方式 1.网易考拉.京东(1190px) 2.知乎(1000px),果壳(1000px),网易新闻(1200px) 媒体查询+定宽 图片类.简 ...

  10. POJ 2217:Secretary(后缀数组)

    题目大意:求两个字符串的公共子串. 分析: 模板题,将两个字符串接起来用不会出现的字符分割,然后求分属两个字符串的相邻后缀lcp的最大值即可. 代码: program work; type arr=. ...