因为这题,气得我火冒三丈!

这数据是不是有问题啊!我用cin代替scanf后居然就AC了(本来一直卡在Test 18)!导致我调(对)试(排)了一个小时!!

UPD:后来细细想想,会不会是因为scanf的读入,数组要开大一点点呢?比如读一个长为\(n\)的字符串,需要一个\(str[n + 1]\)?

题目

就是找出有多少条经过所有可行格子的回路。

插头DP

一直没有时间学习,然后最近膜拜了一下cdq的《基于连通性状态压缩的动态规划问题》,然后写了一裸题。

其实也很好写嘛,不过在转移的时候要万分小心,还有要注意的是记录下第一个可行点最后一个可行点

代码

我的写法是把竖直的那一条轮廓线放在set的最后一位(就是最大那一位)。

//#define debug
//#define local #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <assert.h>
using namespace std; #ifdef debug
#define ep(...) fprintf(stderr, __VA_ARGS__)
#else
#define ep(...) assert(true)
#endif typedef long long i64; const int MaxN = 12; int n, m;
//char A[MaxN][MaxN];
string A[MaxN]; const int MaxHashTable = 30001; #define getbit(x, i) ((x) >> ((i) << 1) & 3)
#define copybit(x, i, b) ((x) | ((b) << ((i) << 1)))
#define clrbit(x, i) ((x) & ~(3 << ((i) << 1)))
#define clrbit2(x, i, j) (clrbit( clrbit(x, j), i))
#define revbit(x, i) ((x) ^ (1 << ((i) << 1))) struct Hash
{
pair<int, i64> A[MaxHashTable];
int n; void update(bool lastone)
{
int i = 0;
if (lastone)
{
while (i < n)
{
if (A[i].first)
{
n --;
A[i] = A[n];
}
else i ++;
}
}
else
{
while (i < n)
{
int s = A[i].first;
if (getbit(s, m)) // assert clrbit(s, m)
{
n --;
A[i] = A[n];
}
else i ++;
}
}
} i64 total()
{
i64 ret = 0;
for (int i = 0; i < n; i ++)
ret += A[i].second;
return ret;
} struct Link
{
int to;
Link *next;
}pool[MaxHashTable], *pool_cur, *info[MaxHashTable];
int pool_counter, pool_mark[MaxHashTable]; void clear()
{
pool_counter ++;
n = 0;
pool_cur = pool;
} #ifdef debug
void print()
{
for (int i = 0; i < n; i ++)
ep("%d %lld\n", A[i].first, A[i].second);
ep("\n");
}
#endif void push(const int &st, const i64 &value)
{
int hash = st % MaxHashTable;
if (pool_mark[hash] != pool_counter)
{
pool_mark[hash] = pool_counter;
info[hash] = NULL;
}
for (Link *p = info[hash]; p; p = p->next)
{
if (A[p->to].first == st)
{
A[p->to].second += value;
return;
}
}
pool_cur->to = n;
pool_cur->next = info[hash];
info[hash] = pool_cur ++;
A[n ++] = make_pair(st, value);
#ifdef debug
assert(n <= MaxHashTable);
#endif
}
}; int getbracket0(const int &s, const int &i)
{
int cnt = 1;
for (int j = i + 1; j < m; j ++)
{
int t = getbit(s, j);
if (t)
{
if (t & 1) cnt --;
else cnt ++;
}
if (! cnt) return j;
}
assert(false);
return -1;
} int getbracket1(const int &s, const int &i)
{
int cnt = -1;
for (int j = i - 1; j >= 0; j --)
{
int t = getbit(s, j);
if (t)
{
if (t & 1) cnt --;
else cnt ++;
}
if (! cnt) return j;
}
assert(false);
return -1;
} int main()
{
#if defined(debug) || defined(local)
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif #ifndef debug
while (true)
#else
for (int a = 0; a == 0; a = 1)
#endif
{
//if (scanf("%d%d\n", &n, &m) != 2) break;
if (! (cin >> n >> m)) break;
int lastrow = -1, lastcol = -1, firstrow = -1;
for (int i = 0; i < n; i ++)
{
//scanf("%s\n", A[i]);
cin >> A[i];
for (int j = 0; j < m; j ++)
if (A[i][j] == '.')
{
if (firstrow == -1) firstrow = i;
lastrow = i;
lastcol = j;
}
} if (lastrow == -1)
{
printf("0\n");
continue;
} static Hash dp[2];
dp[0].clear(), dp[1].clear();
int cur = 0, next = 1;
dp[cur].push(0, 1); for (int i = firstrow; i <= lastrow; i ++)
{
for (int j = 0; j < m; j ++)
{
for (int k = 0; k < dp[cur].n; k ++)
{
int s = dp[cur].A[k].first;
i64 val = dp[cur].A[k].second; int U = getbit(s, j);
int L = getbit(s, m); if (A[i][j] == '.')
{
if (L && U)
{
L &= 1, U &= 1;
if (!L && !U)
{
dp[next].push(revbit( clrbit2(s, j, m), getbracket0(s, j)), val);
}
else if (L ^ U)
{
if (L || (i == lastrow && j == lastcol))
dp[next].push(clrbit2(s, j, m), val);
}
else // assert L && U
{
dp[next].push(revbit( clrbit2(s, j, m), getbracket1(s, j)), val);
}
} else if (L)
{
dp[next].push(copybit(s, m, L), val);
dp[next].push(clrbit( copybit(s, j, L), m), val);
}
else if (U)
{
dp[next].push(s, val);
dp[next].push(clrbit( copybit(s, m, U), j), val);
}
else
{
dp[next].push(copybit( copybit(s, m, 3), j, 2), val);
}
} else if (!U && !L)
{
dp[next].push(s, val);
}
}
swap(cur, next);
dp[next].clear();
ep("for %d %d\n", i, j);
#ifdef debug
dp[cur].print();
#endif
} dp[cur].update(i == lastrow);
} ep("final:\n");
//dp[cur].update(true);
//dp[cur].print();
//printf("%I64d\n", dp[cur].total());
//printf("%lld\n", dp[cur].total());
ep("%lld\n", dp[cur].total());
cout << dp[cur].total() << endl;
} return 0;
}

初探 插头DP的更多相关文章

  1. 初探插头dp

    开学那个月学了点新东西,不知道还记不记得了,mark一下 感觉cdq的论文讲的很详细 题主要跟着kuangbin巨做了几道基础的 http://www.cnblogs.com/kuangbin/arc ...

  2. [专题总结]初探插头dp

    彻彻底底写到自闭的一个专题. 就是大型分类讨论,压行+宏定义很有优势. 常用滚动数组+哈希表+位运算.当然还有轮廓线. Formula 1: 经过所有格子的哈密顿回路数. 每个非障碍点必须有且仅有2个 ...

  3. 插头dp初探

    问题描述 插头dp用于解决一类可基于图连通性递推的问题.用插头来表示轮廓线上的连通性,然后根据连通性与下一位结合讨论进行转移. 表示连通性的方法 与字符串循环最小表示不同,这种方法用于给轮廓线上的联通 ...

  4. 插头dp

    插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...

  5. HDU 4113 Construct the Great Wall(插头dp)

    好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...

  6. HDU 4949 Light(插头dp、位运算)

    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...

  7. 插头DP专题

    建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...

  8. HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...

  9. HDU 1693 Eat the Trees(插头DP)

    题目链接 USACO 第6章,第一题是一个插头DP,无奈啊.从头看起,看了好久的陈丹琦的论文,表示木看懂... 大体知道思路之后,还是无法实现代码.. 此题是插头DP最最简单的一个,在一个n*m的棋盘 ...

随机推荐

  1. SSIS: 使用最大ID和最大日期来增量更新表

    简单三步: 1.  新增变量 MaxID和MaxCreateDate以及Variable 2.  放置一个 Execute SQL  Task ,用SQL 来获取 MaxID和MaxCreateDat ...

  2. 对面向对象的理解—— SAP电面(1)

    对于C++面向对象的理解 面向对象是在结构化设计方法出现很多问题的情况下应运而生的.结构化设计方法求解问题的基本策略是从功能的角度审视问题域.它将应用程序看成实现某些特定任务的功能模块,其中子过程是实 ...

  3. unity之uv贴图画圆弧,圆弧面,不规则图形

    由于最近一直没有时间,所以这篇博客一直没发,下面我说说uv画圆弧,圆面,不规则面拼接. 先来两张效果图 图截的不咋滴,凑合着看吧,画圆弧主要用的贝塞尔曲线画的,我感觉这个比较简单,当然大家也可以使用圆 ...

  4. 设计模式值六大原则——开闭原则(OCP)

    开闭原则(Open Closed Principle)是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的.灵活的系统. 定义: 一个软件实体如类.模块和函数应该对扩展开放,对修改关闭. S ...

  5. linux分区工具fdisk的使用

    fdisk是linux下的一块分区工具,使用简单方便,由于是对系统进行修改,需要root权限. 常用参数如下: fdisk  -l : 列出所有的硬盘信息 直接传入设备名称可进入对该硬盘分区.例如,f ...

  6. Sicily-1006

    一.  题意 这道题就是考排列组合吧,再来就是比较一下字符的下标算一下两个ranking的距离.然后我总结了一个排列和一个组合的实现方法,这道题直接用的是stl 里面的next_permutation ...

  7. UItexfile实时验证输入字符

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementS ...

  8. gdal库的三个使用心得

    作者:朱金灿 来源:http://blog.csdn.net/clever101 最近使用gdal库比较多,就谈谈gdal库的一些使用心得. 第一个是GDALOpen的访问权限参数会影响图像的创建金字 ...

  9. Linux chmod命令具体解释

    仅仅能文件属主或特权用户才干使用该功能来改变文件存取模式.mode能够是数字形式或以who opcode permission形式表示. who是可选的,默认是a(全部用户). 仅仅能选择一个opco ...

  10. iOS 请求数据 error

    解决办法如下: 0x1 ->请求数据时加上缺少的类型 AFHTTPSessionManager *manager = [selfAFHTTPSessionManager];//    manag ...