POJ 1739
楼教主男人八题之一。。。
题目大意:
求从左下角经过所有非障碍点一次到达右下角的方案数
这里不是求回路,但是我们可以考虑,在最下面一行再增加一行,那么就可以当做求此时左下角到右下角的回路总数,那么就转化成了陈丹琦论文的URAL1519的
方法了
但是最后一行添加的格子必须是最后一条直线跑的,也就是除了左下角和右下角中间的点只能有水平方向上的插头
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std;
#define ll long long
const int HASH = ;
const int STATE = ;
const int MAXD = ;
int n , m , enx , eny;
int code[MAXD] , mp[MAXD][MAXD];
bool flag[MAXD][MAXD];//标记位,标记当前点能否作为最终点
ll ans = ;
struct HASHMAP{
int head[HASH] , next[STATE] , state[STATE] , size;
ll f[STATE]; void init(){
size = ;
memset(head , - , sizeof(head));
} void push_in(int st , ll sum){
int h = st%HASH;
for(int i = head[h] ; ~i ; i=next[i]){
if(st == state[i]){
f[i]+=sum;
return ;
}
}
f[size]=sum;
state[size] = st;
next[size] = head[h];
head[h] = size++;
}
}hashmap[]; int num = ;//记录共有的插头数量
void decode(int *code , int m , int st)
{
num = ;
for(int i=m ; i>= ; i--){
code[i] = st&;
st>>=;
if(code[i]) num++;
}
} int encode(int *code , int m)
{
int st=;
for(int i= ; i<=m ; i++){
st<<=;
st |= code[i];
}
return st;
} void shift(int *code , int m) //换行,可理解为将最右侧轮廓线换到了下一行的最左侧
{
for(int i=m ; i>= ; i--) code[i] = code[i-];
code[] = ;
} void dpblank(int i , int j , int cur)
{
int k , left , up;
for(k= ; k<hashmap[cur].size ; k++){
decode(code , m , hashmap[cur].state[k]);
left = code[j-];
up = code[j];
// cout<<"chatou: "<<i<<" "<<j<<" "<<left<<" "<<up<<endl;
if(!left && !up){
if(mp[i][j+] && mp[i-][j]){ //不断向上转移
code[j-] = , code[j] = ;
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
}
else if(!left && up){
if(mp[i][j+]) hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
if(mp[i-][j]){
code[j-] = up , code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
}
else if(left && !up){
if(mp[i-][j]){
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
if(mp[i][j+]){
code[j-] = , code[j] = left;
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
}
else if(left== && up == ){
int cnt = ;
for(int v=j+ ; v<=m ; v++){
if(code[v]==)cnt++;
if(code[v]==)cnt--;
if(!cnt){
code[v]=;
break;
}
}
code[j-] = code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
else if(left == && up == ){
int cnt=;
for(int v=j- ; v>= ; v--){
if(code[v]==)cnt++;
if(code[v]==)cnt--;
if(!cnt){
code[v]=;
break;
}
}
code[j-] = code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
else if(left== && up==){
if(i==enx && j==eny) {
code[j-] = code[j] = ;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
}
else{
code[j-]=code[j]=;
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
}
} void dpblock(int i , int j , int cur)
{
int k , left , up;
for(k= ; k<hashmap[cur].size ; k++){
decode(code , m , hashmap[cur].state[k]);
left = code[j-];
up = code[j];
// cout<<"block: "<<i<<" "<<j<<" "<<left<<" "<<up<<endl;
if(!left && !up){
if(j==m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]); }
}
} void dpselect(int i , int j , int cur)
{
int k , left , up;
for(k= ; k<hashmap[cur].size ; k++){
decode(code , m , hashmap[cur].state[k]);
left = code[j-];
up = code[j];
if(left== && !up){
code[j-] = , code[j] = ;
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
}
} char s[MAXD][MAXD]; void init()
{
for(int i= ; i<=n ; i++){
scanf("%s" , s[i]+);
for(int j= ; j<=m ; j++){
mp[i][j] = s[i][j]=='.';
}
}
for(int i=n ; i>= ; i--)
for(int j= ; j<=m ; j++)
if(mp[i][j]) enx=i , eny=j;
mp[n+][] = , mp[n+][m] = ;
for(int i= ; i<m ; i++) mp[n+][i] = ;
n++;
for(int i= ; i<=m+ ; i++) mp[][i] = ;
for(int i= ; i<=n ; i++) mp[i][m+] = ;
/* for(int i=0 ; i<=n ; i++)
{
for(int j=1 ; j<=m+1 ; j++){
cout<<mp[i][j]<<" ";
}
cout<<endl;
}
cout<<enx<<" "<<eny<<endl;*/
} ll solve()
{
ans = ;
int cur = ;
hashmap[cur].init();
hashmap[cur].push_in( , );
for(int i=n ; i>= ; i--){
for(int j= ; j<=m ; j++){
hashmap[cur^].init();
if(mp[i][j]==) dpblank(i , j , cur);
else if(mp[i][j]==) dpblock(i , j , cur);
else dpselect(i , j , cur);
cur^=;
} }
for(int i= ; i<hashmap[cur].size ; i++) ans+=hashmap[cur].f[i];
return ans;
} int main()
{
// freopen("in.txt" , "r" , stdin);
int cas = ;
while(scanf("%d%d" , &n , &m) , n+m)
{
init();
// printf("Case %d: ",++cas);
if(n== && m==){
printf("%d\n" , );
continue;
}
printf("%I64d\n" , solve());
}
return ;
}
POJ 1739的更多相关文章
- [POJ 1739] Tony's Tour
Link: POJ 1739 传送门 Solution: 这题除了一开始的预处理,基本上就是插头$dp$的模板题了 由于插头$dp$求的是$Hamilton$回路,而此题有起点和终点的限制 于是可以构 ...
- POJ 1739:Tony's Tour
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(插头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,轮廓线DP)
题意:给一个n*m的矩阵,其中#是障碍格子,其他则是必走的格子,问从左下角的格子走到右下角的格子有多少种方式. 思路: 注意有可能答案是0,就是障碍格子阻挡住了去路. 插头DP有两种比较常见的表示连通 ...
- 【POJ】【1739】Tony's Tour
插头DP 楼教主男人八题之一! 要求从左下角走到右下角的哈密顿路径数量. 啊嘞,我只会求哈密顿回路啊……这可怎么搞…… 容易想到:要是把起点和重点直接连上就变成一条回路了……那么我们就连一下~ 我们可 ...
- 插头DP专题
建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...
- 【HDOJ】【2829】Lawrence
DP/四边形不等式 做过POJ 1739 邮局那道题后就很容易写出动规方程: dp[i][j]=min{dp[i-1][k]+w[k+1][j]}(表示前 j 个点分成 i 块的最小代价) $w(l, ...
- 插头DP题目泛做(为了对应WYD的课件)
题目1:BZOJ 1814 URAL 1519 Formula 1 题目大意:给定一个N*M的棋盘,上面有障碍格子.求一个经过所有非障碍格子形成的回路的数量. 插头DP入门题.记录连通分量. #inc ...
随机推荐
- 浅谈 MVP in Android
一.概述 对于MVP(Model View Presenter),大多数人都能说出一二:“MVC的演化版本”,“让Model和View完全解耦”等等.本篇博文仅是为了做下记录,提出一些自己的看法,和帮 ...
- 转载:最大子段和问题(Maximum Interval Sum)
一.问题描述 给定长度为n的整数序列,a[1...n], 求[1,n]某个子区间[i , j]使得a[i]+…+a[j]和最大.或者求出最大的这个和. 例如(-2,11,- ...
- ORACLE CentOS5.6安装
1 准备 CentOS 5.6企业版 oracle11g fs 安装.安装环境为vmware虚拟机.另外,本安装文档非常简洁,但关键步骤都指出来了,其他的都是默认选择,遇到不知该如何选择的操作或者问题 ...
- Sqlserver_自定义函数操作
use Test go if exists( SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'gettime') AND type in ...
- HM中字典编码分析
LZ77算法基本过程 http://jpkc.zust.edu.cn/2007/dmt/course/MMT03_05_2.htm LZ77压缩算法详解 http://wenku.baidu.com/ ...
- iOS开发 判断用户是否开启了定位
- (BOOL)achiveUserLocationStart { CLAuthorizationStatus status = [CLLocationManager authorizationSta ...
- Unity 5 中的全局光照技术详解(建议收藏)
本文整理自Unity全球官方网站,原文:UNITY 5 - LIGHTING AND RENDERING (文章较长,请耐心阅读)简介全局光照,简称GI,是一个用来模拟光的互动和反弹等复杂行为的算法, ...
- 【转】 C++ map的基本操作和使用
1.map简介 map是一类关联式容器.它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响.对于迭代器来说,可以修改实值,而不能修改key. 2.map的功能 自 ...
- 鸟哥的linux私房菜勘误表
博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://github.com/jiangxincode 知乎地址: https://ww ...
- 核心Javascript学习
1. 引言: 1.1. 网页三要素: l HTML(内容) l CSS(外观) l Javascript(行为) 1.2. OOP的相关概念 1). 对象,方法和属性 l 对象就是指"事物 ...