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