http://poj.org/problem?id=1739 (题目链接)

题意

  给出一个n*m的地图,有些是障碍。问从左下角走遍所有非障碍格子一次且仅一次最终到达右下角的路径方案数。

Solution

  插头dp。

  我们给地图的再加上2行:

    .####.

    ......

  那么最后就变成了求一个回路了,思路参见cdq论文。

  UPD:并不是每种转移都需要重新求一遍最小表示法,但是那样写虽然常数略大,代码会整洁很多。虽然有强迫症,但是为了常数,还是把代码更新一下吧。

细节

  细节见代码。

代码

// poj1739
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define MOD 4001
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxd=15,maxs=100010,maxh=4010;
int head[maxh],next[maxs];
int n,m,code[maxd],t[maxd],a[maxd][maxd],size[2],s[2][maxs];
char ch[maxd];
int tot[2][maxs]; void decode(int st) { //解码
for (int i=m;i>=0;i--) {
code[i]=st&7;
st>>=3;
}
}
int encode(int op) { //编码
int cnt=0;int st=0;
if (op) { //有时并不需要重新求最小表示法
memset(t,-1,sizeof(t));t[0]=0;
for (int i=0;i<=m;i++) {
if (t[code[i]]==-1) t[code[i]]=++cnt;
code[i]=t[code[i]];
}
}
for (int i=0;i<=m;i++) st=st<<3|code[i];
return st;
}
void shift() { //换行
for (int i=m;i;i--) code[i]=code[i-1];
code[0]=0;
}
void add(int op,int p,int num) { //更新hash表
int tmp=encode(op),id=tmp%MOD;
for (int i=head[id];i;i=next[i])
if (s[p][i]==tmp) {tot[p][i]+=num;return;}
next[++size[p]]=head[id];s[p][size[p]]=tmp;tot[p][size[p]]=num;
head[id]=size[p];
}
int main() {
while (scanf("%d%d",&n,&m)!=EOF && n && m) {
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++) {
scanf("%s",ch+1);
for (int j=1;j<=m;j++) a[i][j]=ch[j]=='.';
}
a[n+1][1]=a[n+1][m]=1;
for (int i=1;i<=m;i++) a[n+2][i]=1;
n+=2; //加行
int ex=n,ey=m; //终止格显然是无障碍的 int p=0;
tot[0][1]=1;size[0]=1;s[0][1]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) {
p^=1; //滚动
size[p]=0;
memset(head,0,sizeof(head)); //清空hash表
for (int k=1;k<=size[p^1];k++) {
decode(s[p^1][k]); //解码
int left=code[j-1],up=code[j]; //左插头,上插头
if (!a[i][j]) { //该格子为障碍格
code[j-1]=code[j]=0;
if (j==m) shift();
add(0,p,tot[p^1][k]);
continue;
}
if (left && up) { //左、上插头都存在,合并连通块
if (left==up) { //即将合并的两部分在同一个联通分量中
if (i==ex && j==ey) { //只能出现在最后一个格子
code[j]=code[j-1]=0;
if (j==m) shift();
add(0,p,tot[p^1][k]);
}
}
else { //不在同一个联通分量,合并
code[j-1]=code[j]=0;
for (int l=0;l<=m;l++) if (code[l]==left) code[l]=up;
if (j==m) shift();
add(1,p,tot[p^1][k]);
}
}
else if (left || up) { //左、上插头存在一个,连通块不变
int tmp;
if (left) tmp=left;
else tmp=up;
if (a[i][j+1]) { //插头插向右边的格子,这一步一定要先写,因为后面那步需要shift,会破坏code
code[j-1]=0;code[j]=tmp;
add(0,p,tot[p^1][k]);
}
if (a[i+1][j]) { //插头插向下边的格子
code[j-1]=tmp;code[j]=0;
if (j==m) shift();
add(0,p,tot[p^1][k]);
}
}
else { //左、上插头都不存在。新建连通块
if (a[i][j+1] && a[i+1][j]) {
code[j-1]=code[j]=10; //随意设一个一定不会与之前连通块重复的编号
add(1,p,tot[p^1][k]);
}
}
}
}
int ans=0;
for (int i=1;i<=size[p];i++) ans+=tot[p][i];
printf("%d\n",ans);
}
return 0;
}

  

【poj1739】 Tony's Tour的更多相关文章

  1. 【POJ】【1739】Tony's Tour

    插头DP 楼教主男人八题之一! 要求从左下角走到右下角的哈密顿路径数量. 啊嘞,我只会求哈密顿回路啊……这可怎么搞…… 容易想到:要是把起点和重点直接连上就变成一条回路了……那么我们就连一下~ 我们可 ...

  2. 【SPOJ】1825. Free tour II(点分治)

    http://www.spoj.com/problems/FTOUR2/ 先前看了一会题解就自己yy出来了...对拍过后交tle.................. 自己造了下大数据........t ...

  3. 【Codeforces858F】Wizard's Tour [构造]

    Wizard's Tour Time Limit: 50 Sec  Memory Limit: 512 MB Description Input Output Sample Input 4 5 1 2 ...

  4. 【读书笔记】A Swift Tour

    素材:A Swift Tour 推荐下载Playground:Download Playground objc 自己较为熟悉,想熟悉下风头正劲的 swift.就先从官方的入门手册开始撸. 每一小节,我 ...

  5. 【BZOJ3060】[Poi2012]Tour de Byteotia 并查集

    [BZOJ3060][Poi2012]Tour de Byteotia Description 给定一个n个点m条边的无向图,问最少删掉多少条边能使得编号小于等于k的点都不在环上. Input     ...

  6. 【CF1053E】Euler tour

    [CF1053E]Euler tour 题面 CF 洛谷 大概意思是你有一棵树,然而你并不知道这棵树是啥.给你一个确定了一些位置的欧拉序(就是\(ST\)表求\(LCA\)的那个序列),问你是否存在一 ...

  7. 【POJ】【1637】Sightseeing tour

    网络流/最大流 愚人节快乐XD 这题是给一个混合图(既有有向边又有无向边),让你判断是否有欧拉回路…… 我们知道如果一个[连通]图中每个节点都满足[入度=出度]那么就一定有欧拉回路…… 那么每条边都可 ...

  8. Python开发【前端】:JavaScript

    JavaScript入门 JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...

  9. 【python】函数之内置函数

    Python基础 内置函数 今天来介绍一下Python解释器包含的一系列的内置函数,下面表格按字母顺序列出了内置函数: 下面就一一介绍一下内置函数的用法: 1.abs() 返回一个数值的绝对值,可以是 ...

随机推荐

  1. android滚动公告栏

    项目里要用到开奖公告,单行显示向上滚动的TextView,网上随便找了一个控件发现效果还不错改装一下就可以用到项目里.唯一不妥的地方就是字体大小不太好控制,不是正常的字体大小,也没有深究代码,先把工作 ...

  2. select、poll、epoll区别总结

    1 本质上都是同步I/O 三者都是I/O复用,本质上都属于同步I/O.因为三者只是负责通知应用程序什么时候数据准备好了,实际的I/O操作还是在由应用程序处理:如果是异步I/O的话,实际I/O由内核处理 ...

  3. #VSTS日志# TFS 2015 Update 2 RC2新功能

    有段时间没有更新#VSTS日志#了,最近小编太忙,全国各地飞来飞去给各种不同的团队实施敏捷,今天冷不丁一看,呀!TFS 2015 Update 2 RC2都已经发布了.里面好东西不少,列出几个给大家瞧 ...

  4. mysqldump: Got error: 1142: SELECT, LOCK TABLES command denied to user 'root'@'localhost' for table 'accounts' when using LOCK TABLES

    AutoMySQLBackup备份时,出现mysqldump: Got error: 1142: SELECT, LOCK TABLES command denied to user 'root'@' ...

  5. Ignite安装配置——上篇

    Ignite介绍 Ignite 是SolarWinds公司开发的一款数据库性能监控.性能分析并提供优化解决方案的性能检测分析工具,Ignite配置简单.方便:它会收集实时会话数据.服务器资源使用情况, ...

  6. .NET应用架构设计—面向对象分析与设计四色原型模式(彩色建模、领域无关模型)(概念版)

    阅读目录: 1.背景介绍 2.问自己,UML对你来说有意义吗?它帮助过你对系统进行分析.建模吗? 3.一直以来其实我们被一个缝隙隔开了,使我们对OOAD遥不可及 4.四色原型模式填补这个历史缝隙,让我 ...

  7. MySQL(三)

    MYSQL(三) 上一章给大家说的是数据库的视图,存储过程等等操作,这章主要讲索引,以及索引注意事项,如果想看前面的文章,url如下: MYSQL入门全套(第一部) MYSQL入门全套(第二部) 索引 ...

  8. W3School-CSS 列表实例

    CSS 列表实例 CSS 实例 CSS 背景实例 CSS 文本实例 CSS 字体(font)实例 CSS 边框(border)实例 CSS 外边距 (margin) 实例 CSS 内边距 (paddi ...

  9. 微信浏览器的HTTP_USER_AGENT

    在iPhone下,返回   1 Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, lik ...

  10. 配置windows路由表,使电脑同时连接内网外网方法

    1.环境一(系统:windows xp,内网.外网不是同一类地址,内网地址固定): 外网:通过笔记本的无线网卡连接: 内网:通过笔记本的本地连接: 第一步,连接网线,配置本地连接地址,注意IP地址不要 ...