题意:给一个n*m的矩阵,为1时代表空格子,为0时代表障碍格子,问如果不经过障碍格子,可以画一至多个圆的话,有多少种方案?(n<12,m<12)

思路:

  这题不需要用到最小表示法以及括号表示法。

  以一个非障碍格子为单位进行DP转移,所以可以用滚动数组。只需要保存m+1个插头的状态,其中有一个是右插头,其他都是下插头,若有插头的存在,该位为1,否则为0,初始时都是0。

  需要考虑的是,(1)如果两个边缘都是插头,那么必须接上它们;(2)如果仅有一边是插头,则延续插头,可以有两个延续的方向(下和右);(3)如果都没有插头,那么必须另开两个新插头(新连通分量)。

  如下图,记录的状态是:101111。由于是按行来保存状态的,第一个格子需要特殊考虑,将所有状态左移一位,最后的一位就是右方向的边缘。假设上行都有下插头,那么此行初始时是011111,可以看到最左边的是0,表示无右插头,注意:我是按照111110保存的,即最低位是最左边。

  

  初始格子dp[0][0]=1,而答案就是dp[cur][0]了,肯定是无插头存在的状态了,所有的圆圈都是完整的。

 #include <bits/stdc++.h>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
int g[N][N], cur;
LL dp[N][<<N]; void clear()
{
cur^=;
memset(dp[cur], , sizeof(dp[cur]));
} LL cal(int n,int m)
{
dp[][]=; //开始时没有任何插头
for(int i=; i<n; i++) //枚举格子
{
clear();
for(int k=; k<(<<m); k++) dp[cur][k<<]+=dp[cur^][k]; //最高位自动会被忽略
for(int j=; j<m; j++)
{
int r=(<<j), d=(<<(j+)); //r和d 相当于 右和下
clear();
for(int k=; k<(<<(m+)); k++) //枚举状态
{
if(g[i][j]) //空格
{
if( (k&r) && (k&d) ) //两边都有插头:连起来,变无插头
dp[cur][k^r^d]+=dp[cur^][k];
else if( k&r || k&d ) //其中一边有插头:可转两个方向
{
dp[cur][k]+=dp[cur^][k];
dp[cur][k^r^d]+=dp[cur^][k];
}
else //无插头:另开两个新插头
dp[cur][k|r|d]=dp[cur^][k];
}
else //障碍格子
{
if( !(k&r) && !(k&d) )
dp[cur][k]=dp[cur^][k];
}
}
}
}
return dp[cur][];
} int main()
{
//freopen("input.txt", "r", stdin);
int n, m, t, Case=;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
memset(g, , sizeof(g));
memset(dp, , sizeof(dp));
for(int i=; i<n; i++)
for(int j=; j<m; j++)
scanf("%d",&g[i][j]);
printf("Case %d: There are %lld ways to eat the trees.\n", ++Case, cal(n,m));
}
return ;
}

AC代码

  最小表示法实现:

 #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
int g[N][N], n, m, cur, code[N];
struct Hash_Map
{
static const int mod=;
static const int NN=;
int head[mod]; //桶指针
int next[NN]; //记录链的信息
LL status[NN]; //状态
LL value[NN]; //状态对应的DP值。
int size; void clear()
{
memset(head, -, sizeof(head));
size = ;
} void insert(LL st, LL 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[]; void decode(LL s)
{
for(int i=; i<=m; i++)
{
code[i]=s&;
s>>=;
}
}
int cnt[N];
LL encode()
{
LL s=;
memset(cnt, -, sizeof(cnt));
cnt[]=;
for(int i=m,up=; i>=; i--)
{
if(cnt[code[i]]==-) cnt[code[i]]=++up;
code[i]=cnt[code[i]];
s<<=;
s|=code[i];
}
return s;
} void DP(int i,int j)
{
for(int k=; k<hashmap[cur^].size; k++)
{
decode(hashmap[cur^].status[k]);
LL v=hashmap[cur^].value[k]; int R=code[j], D=code[j+]; if(g[i][j]==)
{
if(R==&&D==) hashmap[cur].insert(encode(),v);
continue;
} if(R&&D)
{
code[j]=code[j+]=;
if(R==D) hashmap[cur].insert(encode(),v);
else
{
for(int r=; r<=m; r++)
if(code[r]==R) code[r]=D;
hashmap[cur].insert(encode(), v);
}
}
else if(R||D)
{
R+=D;
if(i+<n)
{
code[j]=R;
code[j+]=;
hashmap[cur].insert(encode(), v);
}
if(j+<m)
{
code[j]=;
code[j+]=R;
hashmap[cur].insert(encode(), v);
}
}
else
{
code[j]=;
code[j+]=;
if(i+<n && j+<m) hashmap[cur].insert(encode(), v);
}
}
} void cal()
{
cur=;
hashmap[cur].clear();
hashmap[cur].insert(,);
for(int i=; i<n; i++)
{
for(int j=; j<hashmap[cur].size; j++) hashmap[cur].status[j]<<=;
for(int j=; j<m; j++)
{
hashmap[cur^=].clear();
DP(i,j);
//cout<<hashmap[cur].size<<endl;
}
}
} LL print()
{
for(int i=; i<hashmap[cur].size; i++)
if(hashmap[cur].status[i]==)
return hashmap[cur].value[i];
return ;
} int main()
{
//freopen("input.txt", "r", stdin);
int t, Case=;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=; i<n; i++)
{
for(int j=; j<m; j++)
{
scanf("%d",&g[i][j]);
}
}
cal();
printf("Case %d: There are %lld ways to eat the trees.\n", ++Case, print());
}
}

AC代码

HDU 1693 Eat the Trees (插头DP)的更多相关文章

  1. hdu 1693 Eat the Trees——插头DP

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1693 第一道插头 DP ! 直接用二进制数表示状态即可. #include<cstdio> # ...

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

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

  3. HDU 1693 Eat the Trees ——插头DP

    [题目分析] 吃树. 直接插头DP,算是一道真正的入门题目. 0/1表示有没有插头 [代码] #include <cstdio> #include <cstring> #inc ...

  4. hdu1693 Eat the Trees [插头DP经典例题]

    想当初,我听见大佬们谈起插头DP时,觉得插头DP是个神仙的东西. 某大佬:"考场见到插头DP,直接弃疗." 现在,我终于懂了他们为什么这么说了. 因为-- 插头DP很毒瘤! 为什么 ...

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

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

  6. HDU - 1693 Eat the Trees(多回路插头DP)

    题目大意:要求你将全部非障碍格子都走一遍,形成回路(能够多回路),问有多少种方法 解题思路: 參考基于连通性状态压缩的动态规划问题 - 陈丹琦 下面为代码 #include<cstdio> ...

  7. HDU 1693 Eat the Trees(插头DP,入门题)

    Problem Description Most of us know that in the game called DotA(Defense of the Ancient), Pudge is a ...

  8. hdu 1693 : Eat the Trees 【插头dp 入门】

    题目链接 题意: 给出一个n*m大小的01矩阵,在其中画线连成封闭图形,其中对每一个值为1的方格,线要恰好穿入穿出共两次,对每一个值为0的方格,所画线不能经过. 参考资料: <基于连通性状态压缩 ...

  9. HDU 1693 Eat the Trees

    第一道(可能也是最后一道)插头dp.... 总算是领略了它的魅力... #include<iostream> #include<cstdio> #include<cstr ...

随机推荐

  1. 微软silverlight Analytics FrameWork

    本文转自:http://kevinfan.blog.51cto.com/1037293/334622/ http://kevinfan.blog.51cto.com/1037293/334622   ...

  2. Android开发--环境搭建和调试技巧

    一:环境搭建 (1)我使用的环境是:window8+Java SDK+Eclipse+Android SDK+ADT 安装步骤:Java SDK-->Eclipse--->ADT---&g ...

  3. 2、css的存在形式及优先级

    一.优先级 简单可以理解为就近原则: <html lang="en"> <head> <meta charset="UTF-8"& ...

  4. CPython里的GIL

    GIL不是Python特性,是CPython解释器特性,因为CPython有垃圾回收机制. GIL 本质是互斥锁,保护解释器安全. 保证线程安全,垃圾回收线程不会和其他线程一起运行. 多个线程不能实现 ...

  5. Python小爬虫,用Python3.X编写

    import urllib.request # 导入urlib.request模块import re # 导入re模块 # 获得每一页的网址并返回def get_url(pageNumber): ne ...

  6. 算法学习--Day10

    今天开始了新一章的学习,前面的题目虽然做了几道,但是我觉得训练量仍然太小了.不过机试确实很多题目,并且难度也有所不同,所以要针对不同的题目进行专门的练习才好.题目类型有些多,等接下来我将搜索的题目写完 ...

  7. KM算法萌新讲解篇

    KM算法   首先了解问题:也就是最大权值匹配: 二分图里,边带了权值,求整幅图里匹配最大/最小的权值 因为接触匈牙利算法的时候看的是找对象系列的博文,所以也自己写一发找对象的博文吧: 算法背景: 信 ...

  8. 渲染路径-实时渲染中常用的几种Rendering Path

    http://www.cnblogs.com/polobymulberry/p/5126892.html?utm_source=tuicool&utm_medium=referral 回到顶部 ...

  9. performSegueWithIdentifier:sender里边的sender是啥意思

    performSegueWithIdentifier:sender里边的sender是啥意思啊?怎样用啊? [self performSegueWithIdentifier:@"pushSi ...

  10. python自建模块显示说明与详情

    通常我们自建模块放在/usr/lib/python2.7/site-packages下面,这样可以python就可以进行调用. 但是,自建模块也要有详细的说明情况,例如查help,可以看出来模块的作用 ...