`
godfrey90
  • 浏览: 56075 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

poj2411解题报告

阅读更多
又是一道状态压缩动态规划的题目,于之前一道有异曲同工之妙,成功AC。
1.算法
(1)首先这道题目和之前的那道炮兵阵地类似,可以以行作为划分进行动态规划,后一行根据前一行的状态来确定。
(2)动态规划最重要的是找状态转移方程。就这道题来说,一共是n行,m列。我们可以这样考虑:我们一行一行的放1*2的牌,在第i行放完以后,必须保证该行所有的格子被填满了。这时记录下第i行向第i+1行凸出的地方。即如果有向第i+1行的凸出,就记录为1,否则记录0,这样就用一个m位的2进制数记录了第i行放完后的状态。比如说00110100就说明第2,4,5的位置向下凸出了。然后开始处理第i+1行,可以根据第i行记录的状态进行放牌。在放牌的时候就要将第i行记录为1的格子给空出来(因为这一个格子被第i行的一个牌占用了)。这样后一行的状态就根据前一行的状态来转移了。我们列出状态转移方程f[i][a]=sum{f[i-1][b]}(其中a为第i行填满以后向i+1行凸起的状态,b为i-1行填满以后向i行凸起的状态)剩下的任务是确定a和b之间的关系。
(3)要确定a,b之间的关系,我们首先要做的一件事情是,列举出一行可能出现的所有状态。在一行中放的牌分为两种情况,一种是这张牌的两格都在本行(横放),一种是这张牌的一格在本行,一个在上面一行或者下面一行(竖放)。我们将横放的牌填充的格子记作0,竖放的牌填充的格子记作1,这样,如001100100,(从右往左看)我们就可以断定第0,1格,第3,4格,第7,8格分别横放着一个牌,第2,5,6格分别竖放着一个牌。我们发现一个特点,横放的牌必须有偶数个0连在一起(原理很简单)。于是我们根据这个特点可以枚举出一行中所有可能的情况,并且把这些情况放到一个数组里,即s,用s_sum记录所有可能情况的个数,即数组的大小。生成s的过程是通过dfs(深搜)完成的。有了s,我们就可以确定状态转移方程中a,b的关系了。b是第i-1行向i行凸出的部分,于是我们遍历一下s,找出符合下列条件的状态s[x]:在b中为1的列上面必须要求s[x]也要为1(这样才能保证s[x]状态不于第i-1行冲突)。这样,a状态就是(s[x]-b)(原理:s[x]中的列为1的时候有两种情况,与上一行的1组成一个牌,或者与下一行的1组成一个牌,即向下凸出,用s[x]-b就减去了前一种情况,剩下的就是后一种情况了)
(4)说说代码:
(a)m,n用来记录输入的行列,s用来记录一行可能存在的所有情况,把一种情况的2进制表示压缩成一个int来表示。s_sum用来记录s数组的大小,即一共有多少种情况。f数组是记录状态的数组,第一个参数i是表示这是第i行填满后的状态,第2个参数x表示状态为x,f的值表示,这个得到这种状态有多少种方案。
(b)读取m,n,并对全局变量进行初始化(很重要,因为有多组测试用例)。(read_in函数)
(c)列出一行中可能有的所有状态,存放在数组s中,这个过程要调用dfs函数进行深度优先搜索。dfs的三个参数的意义,x为处理到第x列,data为当前的状态,num_of0表示前几列有多少个0(这个参数用来判断该列上可以设置的值)(creat_s函数)
(d)最重要的阶段要数dp动态规划了,首先用sum记录2的m次方用于下面的循环使用,然后是设置f数组第0行的值,所有可能的情况的值都为1。接着是通过状态转移方程得出所有f数组的值。最后返回f[n-1][0],即最后一行排满后没有向后凸起的状态的方案数。将其打印。
2.实现
(1)对于f数组存放的值,因为可能较大,要将类型设置为long long,在最后输出的结果的时候要用%I64d来输出。
(2)n,m的位置是等价的,可以交换,把较小的作为n,较大的作为m。这样可以提高效率。
(3)注意变量的初始化,特别是多测试用例的题目。
(4)(((y)&(~s[x]))!=0)的运用很巧妙,可以判断是否符合y中有1的列对应的s[x]的该列也都为1。
3.代码
Problem: 2411		User: godfrey90
Memory: 336K		Time: 141MS
Language: C++		Result: Accepted

#include<cstdio>

int m, n;
int s[150];
int s_sum=0;
long long f[11][2048];

void read_in();
void creat_s();
long long dp();

int main() {
	read_in();
	while (!((m == 0) && (n == 0))) {
		creat_s();
		long long result = dp();
		printf("%I64d\n",result);
		read_in();
	}
	return 0;
}
void read_in() {
	scanf("%d%d", &m, &n);
	if (n > m) {
		int temp = m;
		m = n;
		n = temp;
	}

	for(int i=0;i<150;i++)s[i]=0;
	s_sum=0;
	for(int i=0;i<11;i++)
		for(int j=0;j<2080;j++)
			f[i][j]=0;
}
void dfs(int x, int data,int num_of_0) {
	if (x == m) {
		if(num_of_0%2==1) return;
		s[s_sum++] = data;
		return;
	}
	if (num_of_0%2==1) {
		dfs(x + 1, data,num_of_0+1);
	} else {
		dfs(x + 1, data,num_of_0+1);
		dfs(x + 1, data | (0X1 << x),num_of_0);
	}
}
void creat_s() {
	dfs(0,0,0);
}
long long dp(){
	int sum=1;
	for(int i=0;i<m;i++) sum*=2;

	for(int i=0;i<s_sum;i++){
		f[0][s[i]]=1;
	}
	for(int i=1;i<n;i++){
		for(int x=0;x<s_sum;x++){
			for(int y=0;y<sum;y++){
				if(f[i-1][y]==0) continue;
				if(((y)&(~s[x]))!=0)continue;
				f[i][s[x]-y]+=f[i-1][y];
			}
		}
	}
	return f[n-1][0];
}
分享到:
评论

相关推荐

    poj 3414解题报告

    poj 3414解题报告poj 3414解题报告poj 3414解题报告poj 3414解题报告

    poj 1012解题报告

    poj 1012解题报告poj 1012解题报告poj 1012解题报告poj 1012解题报告

    poj 2329解题报告

    poj 2329解题报告poj 2329解题报告poj 2329解题报告poj 2329解题报告

    POJ 2411 Mondriaan's Dream详细解题报告

    ### POJ 2411 Mondriaan's Dream 解题报告 #### 一、问题背景与定义 **标题**:“POJ 2411 Mondriaan's Dream详细解题报告” **描述**:这份报告提供了针对POJ 2411问题的详细解答过程,适合初学者学习动态规划与...

    poj 1440解题报告

    poj 1440解题报告 poj 1440解题报告 poj 1440解题报告 poj 1440解题报告

    poj 3083解题报告

    poj 3083解题报告poj 3083解题报告poj 3083解题报告poj 3083解题报告

    poj 1659解题报告

    poj 1659解题报告poj 1659解题报告poj 1659解题报告poj 1659解题报告

    poj 3720解题报告

    poj 3720解题报告poj 3720解题报告poj 3720解题报告poj 3720解题报告

    北大poj解题报告

    这个“北大poj解题报告”包含了作者在使用POJ平台解题过程中的学习总结和经验分享,旨在帮助软件工程专业的学生提升编程能力和算法理解。 解题报告通常会涵盖以下几个方面: 1. **基础算法讲解**:解题报告中可能...

    poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告

    poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题...

    poj1691解题报告

    ### poj1691解题报告 #### 题目信息 - **题目名称**:Painting A Board - **时间限制**:1S - **内存限制**:1000K - **提交总数**:62 - **通过总数**:35 - **来源**:...

    acm竞赛----北大poj详细解题报告

    【ACM竞赛与北大POJ解题报告】 在编程竞赛领域,ACM(国际大学生程序设计竞赛,简称ACM/ICPC)是一项极具影响力的比赛,它挑战参赛者的算法设计、问题理解和快速编码能力。北京大学(Peking University)的在线判题...

    80道POJ解题报告

    【标题】"80道POJ解题报告"所涉及的知识点主要集中在ACM(国际大学生程序设计竞赛)和POJ(编程Online Judge系统)上。POJ是北京大学主办的一个在线编程竞赛平台,广泛用于训练和提升程序员的算法设计与实现能力。80...

    北大ACM_POJ_解题报告

    【北大ACM_POJ_解题报告】是北京大学ACM在线评测系统POJ的解题资源集合,这个压缩包包含了对POJ平台上的各种类型ACM竞赛题目的详细解答。ACM,全称国际大学生程序设计竞赛(International Collegiate Programming ...

    POJ 1316解题报告

    【POJ 1316 解题报告】 本题源自北京大学举办的ACM竞赛,题号为POJ 1316,主要涉及算法设计和数组的应用。题目要求找到10000以内的所有self-number,并输出它们。Self-number是一个特殊的整数序列,它的定义是该数...

    poj 2392 解题报告

    《POJ 2392解题报告:高效计算最高堆积高度》 本文将深入解析POJ 2392这个编程题目,该题目要求利用给定的不同高度、耐压性和数量的block,来确定能够堆叠出的最大高度。解决这个问题的关键在于运用排序和动态规划...

    poj2828解题报告

    这篇解题报告主要介绍了如何解决POJ2828这个编程题目。该题目涉及的数据结构是区间树(Interval Tree),这是一种用于高效处理区间查询和修改的树形数据结构。在这个问题中,我们需要根据输入的元素位置和值,构建一...

    ACM Poj Pku 解题报告答案 打包 下载 600多题 史上最全

    ACM Poj Pku 解题报告答案 打包 下载 600多题 史上最全 不是网上乱传的200多题,更不是100多题就挂着10分才能下的题 下了这个 大家也不要浪费分数去下载其它版本的了,基本上都有 共享 一起进步 中国加油 ACMer...

    本人整理的POJ解题报告大全

    【POJ解题报告大全】是我精心整理的一份编程题解集合,主要涵盖了在Programming Online Judge(POJ)平台上遇到的250道经典题目。POJ是一个著名的在线编程竞赛平台,它为程序员提供了大量的算法练习题目,是提高编程...

    北大POJ 大量解题代码

    【标签】"ACM POJ解题报告"是关键词,表明这些代码和报告是围绕ACM竞赛中的POJ平台进行的,ACM是全球知名的学生编程竞赛,旨在测试参赛者的算法知识、编程技能和团队合作能力。POJ(Problem Set Archive)是北京大学...

Global site tag (gtag.js) - Google Analytics