HDU 1693 Eat the Trees (插头DP)
题意:给一个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)的更多相关文章
- hdu 1693 Eat the Trees——插头DP
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1693 第一道插头 DP ! 直接用二进制数表示状态即可. #include<cstdio> # ...
- HDU 1693 Eat the Trees(插头DP)
题目链接 USACO 第6章,第一题是一个插头DP,无奈啊.从头看起,看了好久的陈丹琦的论文,表示木看懂... 大体知道思路之后,还是无法实现代码.. 此题是插头DP最最简单的一个,在一个n*m的棋盘 ...
- HDU 1693 Eat the Trees ——插头DP
[题目分析] 吃树. 直接插头DP,算是一道真正的入门题目. 0/1表示有没有插头 [代码] #include <cstdio> #include <cstring> #inc ...
- hdu1693 Eat the Trees [插头DP经典例题]
想当初,我听见大佬们谈起插头DP时,觉得插头DP是个神仙的东西. 某大佬:"考场见到插头DP,直接弃疗." 现在,我终于懂了他们为什么这么说了. 因为-- 插头DP很毒瘤! 为什么 ...
- HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...
- HDU - 1693 Eat the Trees(多回路插头DP)
题目大意:要求你将全部非障碍格子都走一遍,形成回路(能够多回路),问有多少种方法 解题思路: 參考基于连通性状态压缩的动态规划问题 - 陈丹琦 下面为代码 #include<cstdio> ...
- 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 ...
- hdu 1693 : Eat the Trees 【插头dp 入门】
题目链接 题意: 给出一个n*m大小的01矩阵,在其中画线连成封闭图形,其中对每一个值为1的方格,线要恰好穿入穿出共两次,对每一个值为0的方格,所画线不能经过. 参考资料: <基于连通性状态压缩 ...
- HDU 1693 Eat the Trees
第一道(可能也是最后一道)插头dp.... 总算是领略了它的魅力... #include<iostream> #include<cstdio> #include<cstr ...
随机推荐
- 必须知道的八大种排序算法【java实现】
一.冒泡排序 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成. ...
- linear_classifier.py
import numpy as np from cs231n.classifiers.linear_svm import * from cs231n.classifiers.softmax impor ...
- 用Merge存储引擎中间件实现MySQL分表
觉得一个用Merge存储引擎中间件来实现MySQL分表的方法不错. 可以看下这个博客写的很清楚--> http://www.cnblogs.com/xbq8080/p/6628034.html ...
- Ubuntu12.04下安装VirtualBox
目录: 安装虚拟机VirtualBox 虚拟机VirtualBox安装win7全过程 虚拟机共享文件夹.U盘 一.安装虚拟机VirtualBox VirtualBox下载地址:https://www. ...
- Android开发—— 传递数据
一:使用静态变量传递数据 (1)静态变量传递数据,在目标Activity中声明静态变量,然后使用setText()方法将静态变量的值导出即可: (2)静态变量传递数据,在主Activity中对目标Ac ...
- 部署spark 1.3.1 standalong模式
之前已经写过很多次部署spark 的博客,但是之前部署都是照瓢画葫芦,不得其中的细节,并且以前都是部署spark on yarn 部署环境 scala 2.10.2,jdk 1.6,spark 版本1 ...
- (十四)SpringBoot开发微信授权支付
前提:配置好域名,在公众号配置 一.引用jar包,在pom.xml文件加入依赖 <dependency> <groupId>com.github.binarywang</ ...
- LVS 负载均衡器总结
下面部分原理部分,是从网上摘录,源网址已经无从获取,我将其中一小部分模糊的说明加入了一些自己的理解,仅最大可能让全文容易阅读,也方便自己以后参考,若你是大牛希望能给我一些宝贵的建议,将理解有误的地方加 ...
- iOS 利用模态视图实现带黑色蒙版的底部弹窗
本demo仅适用于iOS8及以上系统. 本文将使用autolayout+storyboard来实现弹窗 第一步.storyboard创建界面 1.打开storyboard 拖一个UIViewcontr ...
- [C++]关于头文件中的防卫式声明
大家知道,我们写.h文件时,通常会加上防卫式声明,有以下两种方式: 1. 宏定义 1 2 3 4 #ifndef _FILENAME_ #define _FILENAME_ //... #endif ...