【插头DP】 POJ 1739 Tony's Tour

通道:http://poj.org/problem?id=1739

题意:左下角走到右下角路径数,单回路。做法就是我们新添2行后寻找回路就可以啦 。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4
  5 using namespace std;
  6
  7 const int MAX_N = 13;
  8 const int MAX_M = 13;
  9 const int HASH = 10007;
 10 const int MAX_S = 1000007;
 11
 12 struct node {
 13     int head[HASH], nxt[MAX_S];
 14     long long dp[MAX_S], st[MAX_S];
 15     int cnt;
 16     void init() {
 17         memset(head, -1, sizeof head);
 18         cnt = 0;
 19     }
 20     void push(long long s, long long v) {
 21         int now = s % HASH;
 22         for(int i = head[now]; ~i; i = nxt[i]) if(st[i] == s) {
 23             dp[i] += v;
 24             return ;
 25         }
 26         st[cnt] = s; dp[cnt] = v;
 27         nxt[cnt] = head[now];
 28         head[now] = cnt++;
 29     }
 30 }d[2];
 31
 32 int n, m;
 33 int ex, ey;
 34
 35 int find_pos(long long s, int p) {
 36     return (s >> (p << 1)) & 3;
 37 }
 38
 39 void tp(long long &s, int p, long long v) {
 40     s &= (~(3ll << (p << 1)));
 41     s |= (v << (p << 1));
 42 }
 43
 44 int find_r(long long s, int p) {
 45     int cnt = 0;
 46     for(int i = p; i <= m; ++i) {
 47         if(find_pos(s, i) == 1) ++cnt;
 48         else if(find_pos(s, i) == 2) --cnt;
 49         if(!cnt) return i;
 50     }
 51 }
 52
 53 int find_l(long long s, int p) {
 54     int cnt = 0;
 55     for(int i = p; i >= 0; --i) {
 56         if(find_pos(s, i) == 2) ++cnt;
 57         else if(find_pos(s, i) == 1) --cnt;
 58         if(!cnt) return i;
 59     }
 60 }
 61
 62 void blank(int i, int j, int cur) {
 63     for(int k = 0; k < d[cur].cnt; ++k) {
 64         long long t = d[cur].st[k];
 65         int l = find_pos(t, j - 1), r = find_pos(t, j);
 66         if(l && r) {
 67             if(l == 1 && r == 1) {
 68                 int tpos = find_r(t, j);
 69                 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 1);
 70                 d[cur ^ 1].push(t, d[cur].dp[k]);
 71             } else if(l == 2 && r == 1) {
 72                 tp(t, j - 1, 0); tp(t, j, 0);
 73                 d[cur ^ 1].push(t, d[cur].dp[k]);
 74             } else if(l == 2 && r == 2) {
 75                 int tpos = find_l(t, j - 1);
 76                 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 2);
 77                 d[cur ^ 1].push(t, d[cur].dp[k]);
 78             } else { // 最后一个非障碍格子
 79                 tp(t, j - 1, 0); tp(t, j, 0);
 80         // 2位为1代表有1个回路,4位为1代表有2个回路
 81                 if (!t) if (i == ex && j == ey) d[cur ^ 1].push(t, d[cur].dp[k]);
 82             }
 83         } else if(l) {
 84             if(i < n) {
 85                 d[cur ^ 1].push(t, d[cur].dp[k]);
 86             }
 87             if(j < m) {
 88                 tp(t, j - 1, 0); tp(t, j, l);
 89                 d[cur ^ 1].push(t, d[cur].dp[k]);
 90             }
 91         } else if(r) {
 92             if(j < m) {
 93                 d[cur ^ 1].push(t, d[cur].dp[k]);
 94             }
 95             if(i < n) {
 96                 tp(t, j - 1, r); tp(t, j, 0);
 97                 d[cur ^ 1].push(t, d[cur].dp[k]);
 98             }
 99         } else { // 新建
100             if(i < n && j < m) {
101                 tp(t, j - 1, 1); tp(t, j, 2);
102                 d[cur ^ 1].push(t, d[cur].dp[k]);
103             }
104         }
105     }
106 }
107
108 void block(int i, int j, int cur) {
109     for (int k = 0; k < d[cur].cnt; ++k) {
110         long long t = d[cur].st[k];
111         int l = find_pos(t, j - 1), r = find_pos(t, j);
112         if (!l && !r) d[cur ^ 1].push(t, d[cur].dp[k]);
113     }
114 }
115
116 char str[17];
117 int a[MAX_N][MAX_M];
118
119 int main() {
120     while (2 == scanf("%d%d", &n, &m)) {
121         if (0 == m && 0 == m) break;
122         memset(a, 0, sizeof a);
123         for (int i = 1; i <= n; ++i) {
124             scanf("%s", str + 1);
125             for (int j = 1; j <= m; ++j)
126                 a[i][j] = str[j] == ‘.‘;
127         }
128         for (int i = 1; i <= m; ++i)
129             a[n + 2][i] = 1;
130         for (int i = 2; i < m; ++i)
131             a[n + 1][i] = 0;
132         a[n + 1][1] = a[n + 1][m] = 1;
133         int cur = 0;
134         long long ans = 0;
135         d[cur].init();
136         d[cur].push(0, 1);
137         n = n + 2;
138         ex = n, ey = m;
139         for (int i = 1; i <= n; ++i) {
140             for (int j = 1; j <= m; ++j) {
141                 d[cur ^ 1].init();
142                 if (a[i][j]) blank(i, j, cur);
143                 else block(i, j, cur);
144                 cur ^= 1;
145             }
146             for (int j = 0; j < d[cur].cnt; ++j)
147                 d[cur].st[j] <<= 2;
148         }
149         for(int i = 0; i < d[cur].cnt; ++i)
150               ans += d[cur].dp[i];
151           printf("%I64d\n", ans);
152     }
153     return 0;
154 }

【插头DP】 POJ 1739 Tony's Tour

时间: 2024-08-26 18:36:29

【插头DP】 POJ 1739 Tony's Tour的相关文章

poj 1739 Tony&#39;s Tour 插头dp模板题

题意: 给一个迷宫,求左下角到右下角的路径数. 分析: 插头dp的模板题,建议先看cdq的论文再看代码,这份代码在模板基础上略微有改动.论文地址http://wenku.baidu.com/view/ed2b3e23482fb4daa58d4b74.html 代码: #include <iostream> using namespace std; const int maxD=16; const int HASH=10007; const int STATE=1000024; int N,M;

【POJ】1739 Tony&#39;s Tour

http://poj.org/problem?id=1739 题意:n×m的棋盘,'#'是障碍,'.'是空白,求左下角走到右下角且走过所有空白格子的方案数.(n,m<=8) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; #define BIT(a,b) ((a)<<((b)<<1)) #

插头DP小结

首先是CDQ<基于连通性状态压缩的动态规划问题>论文上的题目: URAL 1519 Formula 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn = 15; 6 const int HASH = 30007; 7 const int SIZE = 1000010; 8 typedef long lon

插头DP专题

建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议先理解“插头”的概念.然后会HASH表(这个其实是很基础的东西,应该都会的).然后就是DP. 以及特殊题目的特殊处理. 好像一般是求N,M<=12的网格图的某种回路数或某种通路数的方案数. 大体上每个题说几句特殊处理,有问题请纠正....题目的顺序基本上难度递增 另外代码我都是用括号匹配的.因为感觉连通

【POJ 1739】Tony&#39;s Tour

Tony's Tour Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3545   Accepted: 1653 Description A square township has been divided up into n*m(n rows and m columns) square plots (1<=N,M<=8),some of them are blocked, others are unblocked.

【POJ】【1739】Tony&#39;s Tour

插头DP 楼教主男人八题之一! 要求从左下角走到右下角的哈密顿路径数量. 啊嘞,我只会求哈密顿回路啊……这可怎么搞…… 容易想到:要是把起点和重点直接连上就变成一条回路了……那么我们就连一下~ 我们可以在整张图下面加两行:(例:3*5) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 红色的是原来的起点和终点,下面紫色的路径将这两个点连了起来= =然后这题瞬间就变回了Formula 1那题……求哈密顿回路数量,so easy有没有~(其实不这样

POJ 1739:Tony&#39;s Tour

Description A square township has been divided up into n*m(n rows and m columns) square plots (1<=N,M<=8),some of them are blocked, others are unblocked. The Farm is located in the lower left plot and the Market is located in the lower right plot. T

POJ 2411 Mondriaan&#39;s Dream ——状压DP 插头DP

[题目分析] 用1*2的牌铺满n*m的格子. 刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况. So Sad. 然后想到数据范围这么小,爆搜好了.于是把每一种状态对应的转移都搜了出来. 加了点优(gou)化(pi),然后poj上1244ms垫底. 大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可. 然后看了 <插头DP-从入门到跳楼> 这篇博客,怒抄插头DP 然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)

POJ 2411 插头DP

1 //插头DP,算是广义路径的吧. 2 /* 3 我是这样想的,定义填数的为0,未填的为1.然后,初始自然是(0,0).我还定义了整个棋盘的状态,不知是否多此一举. 4 这样,把轮廓线上的格子状态记录.当(I,J)上方的格子为空,必定要填一个竖的.当左边格子为空,当前可填一个横的,也可不填. 5 当左边格子不为空,当前格子必为空...AC. 6 */ 7 8 #include <iostream> 9 #include <cstdio> 10 using namespace st