题目大意:

给定一个图,一部分点'*'作为障碍物,求经过所有非障碍点的汉密尔顿回路有多少条

基础的插头DP题目,对于陈丹琦的论文来说我觉得http://blog.sina.com.cn/s/blog_51cea4040100gmky.html

这个博客写的更容易理解,不过好像这篇博客里的代码有问题,反正是A不了题目的

不过上面的图和思路写的很清楚,可以作为参考

#include <cstdio>
#include <cstring>
#include <iostream> using namespace std;
#define ll unsigned long long
const int HASH_SIZE = ; bool mp[][];
char str[][];
int n, m , k , nn , mm;
int tot[] , bit[] , hash[HASH_SIZE] , state[][HASH_SIZE];
ll dp[][HASH_SIZE] , ans; void init()
{
//每一位用4进制保存,那么对于每一个状态来说都是右移2次,所以这里i*2
for(int i= ; i<= ; i++) bit[i] = i<<;
memset(dp , , sizeof(dp));
tot[] = dp[][] = , ans = k = ;
state[][] = ;
} void hash_in(int s , ll sum)//s表示当前状态,sum是指s状态下共有sum种方式形成
{
// print(s);
// cout<<" "<<sum<<endl;
int p = s%HASH_SIZE;
while(hash[p]){
if(state[k][hash[p]] == s){
dp[k][hash[p]] += sum;
return ;
}
p++;
if(p == HASH_SIZE) p=;
}
hash[p] = ++tot[k];
state[k][hash[p]] = s;
dp[k][hash[p]] = sum;
} void work()
{
for(int i= ; i<=n ; i++){
for(int j= ; j<=m ; j++){
k^= ; //滚动数组
tot[k] = ;
memset(hash , , sizeof(hash));
for(int u= ; u<=tot[-k] ; u++){
int s = state[-k][u] , curs;
ll sum = dp[-k][u];
int p = (s>>bit[j-])& , q = (s>>bit[j])&; //3进制 , 用( , # , )来理解
if(!mp[i][j]){
if(p== && q==) hash_in(s , sum);
}
else{
if(p == && q == ){
if(!mp[i+][j] || !mp[i][j+]) continue;
curs = s + (<<bit[j-]) + (<<bit[j]);
hash_in(curs , sum);
}
else if(!p && q){
if(mp[i][j+]) hash_in(s , sum);
if(mp[i+][j]){
curs = s+q*(<<bit[j-])-q*(<<bit[j]);
hash_in(curs , sum);
}
}
else if(p && !q){
if(mp[i+][j]) hash_in(s , sum);
if(mp[i][j+]){
curs = s - p*(<<bit[j-])+p*(<<bit[j]);
hash_in(curs , sum);
}
}
else if(p+q==){ //可理解为p==1 && q==1
int cnt = ;
for(int v=j+ ; v<=m ; v++){
int w = (s>>bit[v])&;
if(w == ) cnt++;
if(w == ) cnt--;
if(!cnt){
curs = s-(<<bit[v]); //将)转化为( ->状态由2->1 , 减少了一个
break;
}
}
curs = curs-(<<bit[j])-(<<bit[j-]);
hash_in(curs , sum);
}
else if(p+q==){//可理解为p==2 && q==2
int cnt = ;
for(int v=j- ; v>= ; v--){
int w = (s>>bit[v])&;
if(w == ) cnt--;
if(w == ) cnt++;
if(!cnt){
curs= s+(<<bit[v]);
break;
}
}
curs = curs-(<<bit[j])-(<<bit[j-]);
hash_in(curs , sum);
}
else if(p== && q==){
if(i==nn && j==mm)
ans+=sum;
}
else if(p== && q==){
curs = s-(<<bit[j-])-(<<bit[j]);
hash_in(curs , sum);
}
}
}
}
for(int j= ; j<=tot[k] ; j++) state[k][j]<<=;
}
printf("%lld\n" , ans);
} int main()
{
// freopen("in.txt" , "r" , stdin);
while(~scanf("%d%d" , &n , &m))
{
memset(mp , , sizeof(mp));
for(int i= ; i<=n ; i++){
scanf("%s" , str[i]+);
for(int j= ; j<=m ; j++){
mp[i][j] = str[i][j]=='.';
// if(mp[i][j]) cout<<i<<" "<<j<<endl;
if(mp[i][j]) nn=i , mm=j;//记录最后一个可执行块
}
}
init();
work();
}
return ;
}

后来写hdu上的题目的时候觉得kuangbin的表达方式还是很清晰的,所以又将源代码修改成了:

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std;
#define ll unsigned long long
const int HASH = ;
const int STATE = ;
const int MAXD = ;
int n , m , enx , eny;
int code[MAXD] , mp[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[]; void decode(int *code , int m , int st)
{
for(int i=m ; i>= ; i--){
code[i] = st&;
st>>=;
}
} int encode(int *code , int m)
{
int st=;
for(int i= ; i<=m ; i++){
st<<=;
st |= code[i];
}
return st;
} void init()
{
char str[MAXD][MAXD];
for(int i= ; i<=n ; i++){
scanf("%s" , str[i]+);
for(int j= ; j<=m ; j++){
if(str[i][j] == '.'){
mp[i][j] = ;
enx = i , eny = j;
}else mp[i][j] = ;
}
mp[i][m+]=;
mp[n+][i] = ;
}
} 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) //处理可执行格子
{
// cout<<"ok: "<<i<<" "<<j<<endl;
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){
if(!mp[i][j+] || !mp[i+][j]) continue;
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) ans+=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)
{
// cout<<"flase: "<<i<<" "<<j<<endl;
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){
if(j == m) shift(code , m);
hashmap[cur^].push_in(encode(code , m) , hashmap[cur].f[k]);
}
}
} ll solve()
{
ans = ;
int cur = ;
hashmap[cur].init();
hashmap[cur].push_in( , );
for(int i= ; i<=n ; i++){
for(int j= ; j<=m ; j++){
hashmap[cur^].init();
if(mp[i][j]) dpblank(i , j , cur);
else dpblock(i , j , cur);
cur ^= ;
}
}
return ans;
} int main()
{
// freopen("in.txt" , "r" , stdin);
while(~scanf("%d%d" , &n , &m))
{
init();
printf("%I64d\n" , solve());
}
return ;
}

URAL 1519 基础插头DP的更多相关文章

  1. URAL Formula 1 ——插头DP

    [题目分析] 一直听说这是插头DP入门题目. 难到爆炸. 写了2h,各种大常数,ural垫底. [代码] #include <cstdio> #include <cstring> ...

  2. Ural 1519 Formula 1 (DP)

    题意:给定一个 n * m 的矩阵,问你能花出多少条回路. #pragma comment(linker, "/STACK:1024000000,1024000000") #inc ...

  3. 【BZOJ1814】Ural 1519 Formula 1 (插头dp)

    [BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...

  4. 【BZOJ1814】Ural 1519 Formula 1 插头DP

    [BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...

  5. bzoj1814 Ural 1519 Formula 1(插头dp模板题)

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 924  Solved: 351[Submit][Sta ...

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

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

  7. Ural 1519. Formula 1 优美的插头DP

    今天早上学了插头DP的思想和最基础的应用,中午就开始敲了,岐哥说第一次写不要看别人代码,利用自己的理解一点点得写出来,这样才锻炼代码能力!于是下午慢慢地构思轮廓,一点点地敲出主体代码,其实是很磨蹭的, ...

  8. bzoj 1814 Ural 1519 Formula 1 插头DP

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 942  Solved: 356[Submit][Sta ...

  9. 【Ural】1519. Formula 1 插头DP

    [题目]1519. Formula 1 [题意]给定n*m个方格图,有一些障碍格,求非障碍格的哈密顿回路数量.n,m<=12. [算法]插头DP [题解]<基于连通性状态压缩的动态规划问题 ...

随机推荐

  1. Bootstrap段落(正文文本)

    一.Bootstrap段落特点 段落是排版中另一个重要元素之一.在Bootstrap中为文本设置了一个全局的文本样式(这里所说的文本是指正文文本): 1.全局文本字号为14px(font-size). ...

  2. cpu缓存与多线程

    一.cpu缓存结构 CPU速度远高于内存(即如果只考虑CPU和内存因素,程序的性能常常受到内存访问速度的限制,内存访问和运行),为了协调CPU和内存在速度上的差异,在CPU中增加了高速缓存.和计算机存 ...

  3. SqlServer扩展存储过程

    1. 扩展存储过程xp_cmdshell用法: --1.启用 SP_CONFIGURE RECONFIGURE GO SP_CONFIGURE RECONFIGURE GO --2.用法 master ...

  4. VIm vi 使用 汇总

    x 删除当前光标下的字符dw 删除光标之后的单词剩余部分.d$ 删除光标之后的该行剩余部分.dd 删除当前行. c 功能和d相同,区别在于完成删除操作后进入INSERT MODEcc 也是删除当前行, ...

  5. OpenCV3编程入门笔记(4)腐蚀、膨胀、开闭运算、漫水填充、金字塔、阈值化、霍夫变换

    腐蚀erode.膨胀dilate 腐蚀和膨胀是针对图像中的白色部分(高亮部分)而言的,不是黑色的.除了输入输出图像外,还需传入模板算子element,opencv中有三种可以选择:矩形MORPH_RE ...

  6. Machine Learning – 第2周(Linear Regression with Multiple Variables、Octave/Matlab Tutorial)

    Machine Learning – Coursera Octave for Microsoft Windows GNU Octave官网 GNU Octave帮助文档 (有900页的pdf版本) O ...

  7. Dorado7 4版本升级5版本问题汇总

    1.4版本中使用@Bind #dataType1.onInsert没问题,使用@Bind @dataType1.onInsert也没问题,5版本中前者不会触发

  8. 关于智能指针boost::shared_ptr

    boost库中的智能指针shared_ptr, 功能强大, 且开销小,故受到广大coder的欢迎. 但在实际的使用过程中,笔者也发现了一些不足. 1.定制的删除器 shared_ptr除了可以使用默认 ...

  9. python 基础学习(字典对象,set对象)

    1.dict 字典对象 a.定义对象 d={'a':14,'b':12}b.通过key获取value d['a'] 方法1.判断key是否存在 if 'a' in d: d['a']方法2:通过用ge ...

  10. java中的异常和处理

    算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数组负下标异常:NegativeAr ...