ZOJ1100 状压DP +深搜

记得做过类似于这类题目是可以用组合数学方法来解决的,可惜淡忘了,也找不到了,看了网上的也有人提到过可以用组合公式解决,可是没人做,都是用了状压DP的方法,这个状压很难讲清楚吧,推荐两篇

第一遍大体看看这个:http://blog.csdn.net/crux_d/article/details/2206736

想要具体实现的时候看看他的解析:http://blog.csdn.net/yan_____/article/details/8719748

#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>
#include<cctype>

#define ll long long

#define LL __int64

#define eps 1e-8

#define inf 0xfffffff

//const LL INF = 1LL<<61;

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int > P;
//vector<pair<int,int> > ::iterator iter;
//
//map<ll,int >mp;
//map<ll,int >::iterator p;

ll dp[12][10000];//第i行状态为j的放置方法数

int binary[15000][2];//[i][0]表示当前这一行的状态,[i][1]表示与[i][0]相匹配的下一行的状态,因为竖着放会影响下一行

int w,h,cnt;

void init() {
	cnt = 0;
	memset(dp,0,sizeof(dp));
}

void dfs(int n,int now,int nex) {
	if(n > w)return;//还有个n+2的,所以有可能直接大于w,而不会产生等于w
	if(n == w) {
		binary[cnt][0] = now;
		binary[cnt++][1] = nex;
		return;
	}
	dfs(n+2,(now<<2) + 3,(nex<<2) + 3);
	dfs(n+1,(now<<1) + 1,nex<<1);
	dfs(n+1,now<<1,(nex<<1) + 1);
}

int main() {
	while(scanf("%d %d",&w,&h),w + h) {
		init();
		dfs(0,0,0);
		dp[0][(1<<w) - 1] = 1;//边界要填满1
		for(int i=0;i<h;i++)
			for(int j=0;j<cnt;j++)
				dp[i+1][binary[j][1]] += dp[i][binary[j][0]];//下一行的与当前一行的相匹配,所以可递推
		printf("%lld\n",dp[h][(1<<w) - 1]);
	}
	return 0;
}

ZOJ1100 状压DP +深搜,布布扣,bubuko.com

时间: 2024-10-13 12:04:34

ZOJ1100 状压DP +深搜的相关文章

hdu5305(2015多校2)--Friends(状压,深搜)

Friends Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 668    Accepted Submission(s): 313 Problem Description There are n people and m pairs of friends. For every pair of friends, they can cho

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)

2017.8.15 [Haoi2016]字符合并 区间dp+状压dp

[题目描述] 有一个长度为n的01串,你可以每次将相邻的k个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这k个字符确定.你需要求出你能获得的最大分数. [输入格式] 第一行两个整数n,k. 接下来一行长度为n的01串,表示初始串.输入的的相邻字符之间用一个空格隔开. 接下来2k行,每行一个字符ci和一个整数wi,ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符, wi表示对应的第i种方案对应获得的分数. [输出格式] 输出一个整数表示答案. [

zoj 3675 状压dp

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4918 昨天的排位,最初我还以为思维题,然后队友说状压DP,直接放弃,赛后看了队友的代码,在搜下网上的,发现队友的代码居然是最短的,膜拜啊~~~~~~~ 思路是队友 A.L.的 dp[s]=min(dp[s],dp[s']+1) 其中s'可以由s通过一次正着剪指甲或者反着剪指甲达到 至于内层循环,0-m,是因为----从剪指甲刀的最后一位看,最后一位从0移动到m,足够所有情况了

HDOJ 1560 DNA sequence 状压dp 或 IDA*

http://acm.hdu.edu.cn/showproblem.php?pid=1560 题意: 给不超过8个子串,每个子串最多5位,且都只包含ATCG,求最短的母串长度. 分析: 又是上个月写的,所以有点忘了..正解是IDA*.然后可以状压dp,记忆化搜索.dp[i],i用6进制表示,每位表示对应的子串匹配那么多长度所需要的最短母串长度.比如两个子串,13=2*6^1+1*6^0,dp[13]就表示第一个串匹配了第一位,第二个串匹配前两位所需要的最短母串长度. 状态讲完了,不过实际上程序里

HDU-4771 Stealing Harry Potter&#39;s Precious 状压DP+BFS

哈利波特假期回姨夫家的时候会把他的宝贝藏在地精银行,现在要偷他的宝贝,银行的房间分为可破坏与不可破坏两种,其实就是可到达与不可到达,然后给出哈利的k个宝贝放的位置,如果能全部拿到输出最小的步数,不能拿到则输出-1,用BFS搜索,最先搜到的肯定就是步数最小的,搜不到则输出-1.最近做的好多DP题都跟搜索有关系,看来还是多方面都得会才行啊. #include <iostream> #include <cstdio> #include <cmath> #include <

HDOJ 4906 Our happy ending 状压DP(数位DP?)

http://acm.hdu.edu.cn/showproblem.php?pid=4906 题意: N个数的序列,每个数可以选择填0-L,如果一个序列可以选出某些数,他们的和为K,那么这个序列就是”好序列“,给定N<=20,K<=20,0<=L<=10^9,问好序列的个数. 分析: N和K很小,所以要想办法利用这个特性(状压?搜索?).虽然L很大,但实际上一个数大于K的时候,肯定是不能选他组成K的.我们就先考虑L<=K的做法. 然后还是考虑不出来.. 好吧,看题解吧.. 目

poj1185炮兵阵地状压dp

压前两行的状态很容易想到,但是 直接搞  (1<<10) * (1<<10)  空间时间都明显受不了, 但是经过高人指点,你会发现:枚举每一行可行的状态,其实并不多,预先打表处理,不用 1->(1<<10)枚举每一种状态.. 然后记忆化搜就ok了. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include &

poj 2441 Arrange the Bulls 状压dp入门

题意: 将n头牛和m个栏做匹配,求匹配方案数. 分析: 开始暴搜tle了,还是要用状压dp,dp[i][s]表示前i头牛匹配栏的状态为s时可行的方案数. 代码: //poj 2441 //sep9 #include <iostream> using namespace std; const int maxN=21; int dp[2][1<<maxN]; int a[maxN][maxN]; int main() { int n,m; scanf("%d%d",