POJ 1739 Tony's Tour (插头DP,轮廓线DP)
题意:给一个n*m的矩阵,其中#是障碍格子,其他则是必走的格子,问从左下角的格子走到右下角的格子有多少种方式。
思路:
注意有可能答案是0,就是障碍格子阻挡住了去路。
插头DP有两种比较常见的表示连通信息的方式:
(1)最小表示法
(2)括号表示法
本文用括号表示法实现。左括号为1,右括号为2,用两个位来表示。轮廓线上最多需要表示9个插头信息,那么就是18个位即可。插头的状态转移有如下几种:
(1)右插头和下插头都是同个方向的括号,则合并他们,再将对应的两外两个半括号给改成一对。比如 ((())) 合并完变成##()(),橙色的就是需要改的地方。
(2)右插头是')',下插头是'(',则合并他们,且无需任何修改。
(3)右插头是'(',下插头是')',则不能合并,因为一旦合并,肯定是组成1个圆了,就会有多个连通分量的产生。自己画画就知道了。
(4)右插头是'(',下插头是')',只有在最后一个非障碍格子(按行从左到右遍历的)的时候才可以合并,
(5)右/下插头只有1个插头存在,那么可以延续它,可以分别往下和右两个方向。
(6)没有插头,那么只能另开一对新括号了,分别对应右和下插头的位置。
(7)障碍格子,只有该位置的两个插头都是空的时候才可以转移,且轮廓线无需修改。
因为状态本来就不多,用哈希表来存状态会比较快且比较省时间,哈希表实现是摘别人的。每次只需要用上一个格子中的状态来转移到当前格子的状态。本题是不能有连通分量产生的,所以只需要在初始的状态设置起点和终点是一对括号,那就相当于在找哈密顿回路了,和Formula 1就一样了。
//#include <bits/stdc++.h>
#include <iostream>
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
char g[N][N];
int cur, n, m, ex, ey;
struct Hash_Map
{
static const int mod=;
static const int N=;
int head[mod]; //桶指针
int next[N]; //链
int status[N]; //状态
LL value[N]; //状态对应的DP值。
int size;
void clear()
{
memset(head, -, sizeof(head));
size = ;
} void insert(int st, LL val) //插入状态st的值为val
{
int h = st%mod;
for(int i=head[h]; i!=-; i=next[i])
{
if(status[i] == st) //这个状态已经存在,累加进去。
{
value[i] += val;
return ;
}
}
status[size]= st; //新的
value[size] = val;
next[size] = head[h] ; //新插入的元素在队头
head[h] = size++;
}
}hashmap[]; int getbit(int s,int pos) //取出状态s的第pos个插头
{
int bit=;
if(s&(<<*pos)) bit+=;
if(s&(<<*pos+)) bit+=;
return bit;
}
int setbit(int s,int pos,int bit) //将状态s的第pos个插头设置为bit
{
if(s&(<<*pos )) s^=<<*pos;
if(s&(<<*pos+)) s^=<<*pos+;
return s|(bit<<*pos);
} int Fr(int s,int pos,int bit) //寻找状态s的第pos个插头对应的右括号。
{
int cnt=;
for(pos+=; pos<m; pos++)
{
if(getbit(s,pos)==-bit) cnt++;
if(getbit(s,pos)==bit) cnt--;
if(cnt==-) return setbit(s, pos, -bit);
} }
int Fl(int s,int pos,int bit) //寻找状态s的第pos个插头对应的左括号。
{
int cnt=;
for(pos--; pos>=; pos--)
{
if(getbit(s,pos)==-bit) cnt++;
if(getbit(s,pos)==bit) cnt--;
if( cnt==-) return setbit(s, pos, -bit);
} } void DP(int i,int j) //状态转移
{
for(int k=; k<hashmap[cur^].size; k++)
{
int s=hashmap[cur^].status[k];
int v=hashmap[cur^].value[k];
int R=getbit(s,j), D=getbit(s,j+);
if(g[i][j]=='.')
{
if(R && D) //两个括号
{
int t=setbit(s,j,)&setbit(s,j+,);
if(R==D) //同个方向的括号
{
if(R==) t=Fr(t,j,); //要改
else t=Fl(t,j,);
hashmap[cur].insert(t,v);
}
else if( R== && D== ) //不同方向括号
hashmap[cur].insert(t,v);
else if(i==ex&&j==ey)
hashmap[cur].insert(t,v);
}
else if(R || D) //仅1个括号
{
hashmap[cur].insert(s,v);
int t;
if(R) t=setbit(setbit(s,j,),j+,R);
else t=setbit(setbit(s,j+,),j,D);
hashmap[cur].insert(t,v);
}
else //无括号
hashmap[cur].insert( setbit(s,j,)|setbit(s,j+,), v);
}
else if(R==&&D==) //障碍格子
hashmap[cur].insert(s, v);
}
}
void cal()
{
for(int i=; i<n; i++)
{
cur^=;
hashmap[cur].clear();
for(int j=; j<hashmap[cur^].size; j++) //新行,需要左移一下状态。
if( getbit( hashmap[cur^].status[j], m)== )
hashmap[cur].insert( hashmap[cur^].status[j]<<, hashmap[cur^].value[j] );
for(int j=; j<m; j++)
{
cur^=;
hashmap[cur].clear();
DP(i,j);
if(i==ex && j==ey) return ; //终点
}
}
} bool print()
{
for(int i=; i<hashmap[cur].size; i++) //寻找轮廓线状态为0的值。
{
int s=hashmap[cur].status[i];
if(s==)
{
printf("%lld\n", hashmap[cur].value[i]);
return true;
}
}
return false;
}
int main()
{
freopen("input.txt", "r", stdin);
while(scanf("%d%d",&n,&m), n+m)
{
ex=ey=cur=;
for(int i=n-; i>=; i--) scanf("%s",g[i]); //反向存
for(int i=; i<n; i++) //寻找终点格子:ex和ey
for(int j=; j<m; j++)
if( g[i][j]=='.' )
ex=i,ey=j; hashmap[cur].clear();
hashmap[cur].insert(setbit(,,)|setbit(,m-,), ); //初始状态
cal();
if(!print()) puts(""); //无路可达
}
return ;
}
AC代码
附上哈希表实现:
struct Hash_Map
{
static const int mod=;
static const int N=;
int head[mod]; //桶指针
int next[N]; //记录链的信息
int status[N]; //状态
LL value[N]; //状态对应的DP值。
int size;
void clear() //清除哈希表中的状态
{
memset(head, -, sizeof(head));
size = ;
} void insert(int st, LL val) //插入状态st的值为val
{
int h = st%mod;
for(int i=head[h]; i!=-; i=next[i])
{
if(status[i] == st) //这个状态已经存在,累加进去。
{
value[i] += val;
return ;
}
}
status[size]= st; //找不到状态st,则插入st。
value[size] = val;
next[size] = head[h] ; //新插入的元素在队头
head[h] = size++;
}
}hashmap[];
Hash_Map
POJ 1739 Tony's Tour (插头DP,轮廓线DP)的更多相关文章
- [POJ 1739] Tony's Tour
Link: POJ 1739 传送门 Solution: 这题除了一开始的预处理,基本上就是插头$dp$的模板题了 由于插头$dp$求的是$Hamilton$回路,而此题有起点和终点的限制 于是可以构 ...
- POJ 1739 Tony's Tour(插头DP)
Description A square township has been divided up into n*m(n rows and m columns) square plots (1< ...
- POJ 1739 Tony's Tour (DP)
题意:从左下角到右下角有多少种走法. 析:特殊处理左下角和右下角即可. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000 ...
- 【POJ】1739 Tony's Tour
http://poj.org/problem?id=1739 题意:n×m的棋盘,'#'是障碍,'.'是空白,求左下角走到右下角且走过所有空白格子的方案数.(n,m<=8) #include & ...
- 【POJ】【1739】Tony's Tour
插头DP 楼教主男人八题之一! 要求从左下角走到右下角的哈密顿路径数量. 啊嘞,我只会求哈密顿回路啊……这可怎么搞…… 容易想到:要是把起点和重点直接连上就变成一条回路了……那么我们就连一下~ 我们可 ...
- 轮廓线DP:poj 2279 Mr. Young's Picture Permutations
poj 2279 Mr. Young's Picture Permutations \(solution:\) 首先摘取一些关键词:(每行不超过它后面的行)(每排学生安排高度从左到右减少)(学生的高度 ...
- Luogu P3886 [JLOI2009]神秘的生物 最小表示法,轮廓线DP,插头DP,动态规划
亲手写掉的第一道最小表示法!哈哈哈太开心啦~ 不同于以往的几个插头\(dp\),这个题目的轮廓线是周围的一圈\(n\)个格子.而其所谓"插头"也变成了相邻格子的所属连通分量编号,并 ...
- POJ 3254 Corn Fields (状压DP,轮廓线DP)
题意: 有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)? 思路: 明显的状压DP啦,只是怎样 ...
- poj 2411 Mondriaan's Dream (轮廓线DP)
题意:有一个n*m的棋盘,要求用1*2的骨牌来覆盖满它,有多少种方案?(n<12,m<12) 思路: 由于n和m都比较小,可以用轮廓线,就是维护最后边所需要的几个状态,然后进行DP.这里需 ...
随机推荐
- SecureCRT rz上传文件失败
SecureCRT 将 Windows 上的文件传至 Linux 端,小的文件没有问题能够正常上传,但是对于几百M的文件往往上传过程中失败. 解决办法:使用 rz -be,并且去掉对话框中" ...
- layui 复选框checkbox 全选写法
前语:本来我是不想写layui框架的博客的,有的时候数据经过layui渲染后原生的写法就取不到值了,一定要用它框架的写法,实在蛋疼,故写之,以后用到可以省点时间去度娘! HTML: <div i ...
- Flutter实战视频-移动电商-06.Dio基础_Get请求和动态组件协作
博客地址: https://jspang.com/post/FlutterShop.html#toc-0ee 编写页面代码 创建动态组件HomePage,原来的代码是静态的我们这里就去掉就可以了. 然 ...
- Junit使用注意点
注意点 1. 使用了@BeforeClass后@Ignore将会失效
- 让App飞久一点
此文已由作者杨晓授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 本文从作者所在项目进行的耗电量测试入手,介绍了移动端App耗电量测试的一些基本概念和方法,重点介绍了iOS应用 ...
- 【废弃中】JavaScript 内置Object
创建: 2017/09/24 更新: 2018/01/22 增加window对象内容的链接 更改标题: [JavaScript 主要的自带Object] -> [JavaScript 内置Obj ...
- 381. Insert Delete GetRandom O(1) - Duplicates allowed
Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...
- lightoj 1034【强连通+缩点】
思路: 缩点,计算入度为0点的个数即可: #include<bits/stdc++.h> using namespace std; typedef long long LL; const ...
- 50 个加速包都抢不到车票,还不如这个 Python 抢票神器!
又到了一年一度的抢票大战,本来就辛苦劳累了一年,想着可以早点订到票跟家里人团聚.所以有挺多的人,宁愿多花些钱去找黄牛买票.但今年各种抢票软件的横行,还有官方出的加速包,导致连黄牛都不敢保证能买到票.你 ...
- nginx 设置websocket支持
#websocket======相关 proxy_read_timeout 60m; proxy_http_version 1.1; proxy_set_header Upgrade $http_up ...