poj2411

在人指导下第一次做,提交了10次才AC。汗颜啊。

错点1:main函数必须返回int,不然“格式错误”

错点2:让是否继续有测试用例为循环条件,不然“超时”。

错点3:没考虑到number结果可能非常大,int不够,要用long long,输出使用%I64d。不然“结果错误”。


解题思路:http://godfrey90.iteye.com/blog/723732.

1.很容易想到先看第一行有多少种结果,针对每一种结果,第二行又有多少相应结果,依次到最后一行,所有叶子结点的和数目就是结果。

2.由于题目的条件限制,第一行有若干种组合,且为数目最多的,接下来的行都是第一行结果的子集。因此可以构造辅助数组status,存放所有的可能结果,构建一个二维数组number,每一格number[i][j]代表第i行可以取结果status[j]的数目。这样只要计算到最后一行,取出所有可能的结果,把数目加起来就是结果。由第一行推到最后一行,可以用动态规划。

3.对于适用于每一行的status,易想到横向取0,竖向取1.根据规律一行必须两个0相连,枚举出所有结果(dfs)。

4.对于具体每一行的值,status并不能确定其图形,因为竖牌可以是开始,也可以是末尾。因此规定如果向下凸为1,否则为0.这样设有规律:若第i行j位置为1,则i+1行j位置必为0,status在j位置必取1;若0,则i+1行在j位置任意,status在j位置也任意;这个规律可以帮助确定:若number[i][j]不为零(代表可取值j),则i+1行可取哪些值。这样就完成了从第i行推到第i+1行。

5.对于最后一行,只有0值有意义,因为不能再有向下凸起。所以返回number[i-1][0]即可。


Source Code

Problem: 2411 User: mtawaken
Memory: 340K Time: 79MS
Language: C++ Result: Accepted
  • Source Code

  • #include<cstdio>  
    
    int status[145];
    int s_size;
    long long number[11][2048];
    int w,h;
    int sum;
    
    
    void dfs(int pos,int data,int num_of_0){	
    	if(pos==w){
    		if(num_of_0%2==1)return;
    		status[s_size++]=data;
    		return;
    	}	
    	if(num_of_0%2==1)		
    		dfs(pos+1,data,num_of_0+1);
    	else{		
    		dfs(pos+1,data,num_of_0+1);
    		dfs(pos+1,data|(0x1<<pos),num_of_0);
    	}
    }
    
    void dp(){
    	
    	for(int i=1;i<h;i++)
    		for(int j=0;j<s_size;j++)
    			for(int k=0;k<sum;k++){
    				if(number[i-1][k]==0)continue;
    				if((k&(~status[j]))!=0)continue;
    				number[i][status[j]-k]+=number[i-1][k];
    			}
    }
    
    
    bool init(int h,int w){
    	if(w>11||w<=0)return false;
    	if(h>11||h<=0)return false;
    	sum=1;
    	for(int i=0;i<w;i++)sum*=2;
    	for(int i=0;i<11;i++)
    		for(int j=0;j<sum;j++)
    			number[i][j]=0;
    	s_size=0;
    	return true;
    }
    
    void create_status(){
    	dfs(0,0,0);
    }
    
    long long generate_number_matrix(){	
    	for(int i=0;i<s_size;i++){
    		number[0][status[i]]=1;
    	}
    	dp();
    	
    	return number[h-1][0];
    }
    
    
    int main(){
    	while(scanf("%d%d", &h, &w)==2){
    		if(!init(h,w))continue;
    		create_status();
    		long long res = generate_number_matrix();
    		printf("%I64d\n",res);
    	}
    	return 0;
    }
    


                
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值