【poj1739】 Tony's Tour
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的更多相关文章
- 【POJ】【1739】Tony's Tour
插头DP 楼教主男人八题之一! 要求从左下角走到右下角的哈密顿路径数量. 啊嘞,我只会求哈密顿回路啊……这可怎么搞…… 容易想到:要是把起点和重点直接连上就变成一条回路了……那么我们就连一下~ 我们可 ...
- 【SPOJ】1825. Free tour II(点分治)
http://www.spoj.com/problems/FTOUR2/ 先前看了一会题解就自己yy出来了...对拍过后交tle.................. 自己造了下大数据........t ...
- 【Codeforces858F】Wizard's Tour [构造]
Wizard's Tour Time Limit: 50 Sec Memory Limit: 512 MB Description Input Output Sample Input 4 5 1 2 ...
- 【读书笔记】A Swift Tour
素材:A Swift Tour 推荐下载Playground:Download Playground objc 自己较为熟悉,想熟悉下风头正劲的 swift.就先从官方的入门手册开始撸. 每一小节,我 ...
- 【BZOJ3060】[Poi2012]Tour de Byteotia 并查集
[BZOJ3060][Poi2012]Tour de Byteotia Description 给定一个n个点m条边的无向图,问最少删掉多少条边能使得编号小于等于k的点都不在环上. Input ...
- 【CF1053E】Euler tour
[CF1053E]Euler tour 题面 CF 洛谷 大概意思是你有一棵树,然而你并不知道这棵树是啥.给你一个确定了一些位置的欧拉序(就是\(ST\)表求\(LCA\)的那个序列),问你是否存在一 ...
- 【POJ】【1637】Sightseeing tour
网络流/最大流 愚人节快乐XD 这题是给一个混合图(既有有向边又有无向边),让你判断是否有欧拉回路…… 我们知道如果一个[连通]图中每个节点都满足[入度=出度]那么就一定有欧拉回路…… 那么每条边都可 ...
- Python开发【前端】:JavaScript
JavaScript入门 JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...
- 【python】函数之内置函数
Python基础 内置函数 今天来介绍一下Python解释器包含的一系列的内置函数,下面表格按字母顺序列出了内置函数: 下面就一一介绍一下内置函数的用法: 1.abs() 返回一个数值的绝对值,可以是 ...
随机推荐
- Java和WebSocket开发网页聊天室
小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ Java和WebSocket开发网页聊天室 一.项 ...
- 编写Javascript类库(jQuery版) - 进阶者系列 - 学习者系列文章
这些年主要关注于项目管理方面的工作,编码就比较少了.这几天比较空闲,就想把原来的经验沉淀下来,一个是做好记录,以后如果忘记了还能尽快找回来,第二个是写写博文,算是练练手笔吧. 言归正传,这次写的是Ja ...
- 下一代Asp.net开发规范OWIN(1)—— OWIN产生的背景以及简单介绍
随着VS2013的发布,微软在Asp.Net中引入了很多新的特性,比如使用新的权限验证模块Identity, 使用Async来提高Web服务器的吞吐量和效率等.其中一个不得不提的是OWIN和Katan ...
- MySQL如何导出带日期格式的文件
一网友问在MySQL中如何只用SQL语句导出带日期格式的文件.觉得有点意思,于是尝试了一下.导出文件使用SELECT INTO OUTFILE 但是OUTFILE后面的值不能使用变量,所以只能使用动态 ...
- MySQL高可用架构之MHA
简介: MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是 ...
- mac xcode c++ cin cout注意细节一
#include <iostream> using namespace std; 要同时存在 要不然std命名空间无法生效
- 删除docker的运行目录出错
1. 错误类型
- extjs学习资料
ExtJs 入门教程 1.Extjs5.1.0教程云盘地址 http://pan.baidu.com/s/1qYhHiEw 2.Extjs3.x如下: ExtJs 入门教程一[学习方法] ExtJ ...
- 安装 Visual Studio Web Tools 的奇怪问题
安装Microsoft ASP.NET 5 RC 1 时提示 0x80070005 - 拒绝访问 日志文件为 [1968:3F64][2015-11-20T10:08:36]i010: Launchi ...
- Qt 之 入门例程 (一)
以 “Hello Qt” 为例,介绍如何建立一个 Qt 工程 . 1 QLabel 例程 QLabel 继承自 QFrame (继承自 QWidget),主要用来显示文本和图片. 1.1 Hell ...