在人指导下第一次做,提交了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; }