搭积木
题目描述:
小明对搭积木非常感兴趣。他的积木都是同样大小的正立方体。在搭积木时,小明选取 m 块积木作为地基,将他们在桌子上一字排开,中间不留空隙,并称其为第0层。随后,小明可以在上面摆放第1层,第2层,……,最多摆放至第n层。摆放积木必须遵循三条规则:
规则1:每块积木必须紧挨着放置在某一块积木的正上方,与其下一层的积木对齐;规则2:同一层中的积木必须连续摆放,中间不能留有空隙;规则3:小明不喜欢的位置不能放置积木。
其中,小明不喜欢的位置都被标在了图纸上。图纸共有n行,从下至上的每一行分别对应积木的第1层至第n层。每一行都有m个字符,字符可能是‘.’或‘X’,其中‘X’表示这个位置是小明不喜欢的。现在,小明想要知道,共有多少种放置积木的方案。他找到了参加ACM的你来帮他计算这个答案。由于这个答案可能很大,你只需要回答这个答案对1000000007(十亿零七)取模后的结果。注意:地基上什么都不放,也算作是方案之一种。
输入
输入数据的第一行有两个正整数n和m,表示图纸的大小。随后n行,每行有m个字符,用来描述图纸 。每个字符只可能是‘.’或‘X’。
输出
输出一个整数,表示答案对1000000007取模后的结果。
样例输入1
2 3
..X
.X.
样例输出1
4
样例输入2
3 3
..X
.X.
...
样例输出 2
16
#include<iostream>
using namespace std;
#include<map>
map<string,int> mp;//定义map集合,查重
int m,n;
char arr[101][101];
int sum=0;
void disp(){//为了方便理解,将所有符合条件的积木都输出
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cout<<arr[i][j]<<ends;
}
cout<<endl;
}
}
bool fun(){//查重
string s;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
s+=arr[i][j];
}
}
if(mp[s])
return false;
mp[s]++;
return true;
}
bool fun2(int x,int y){//判断该位置是否可以放置积木
if(arr[x][y]!='X'){//如果该位置不为'X'
if(x==m-1){//如果在最底层
if(y==0||arr[x][y-1]=='O')//判断处在第一列或者旁边列放置了积木,因为题目要求积木要连续放置
return true;
}else{//不在第一层,就要多满足一个条件,即 该积木所在的下一行有积木
if((y==0||arr[x][y-1]=='O')&&arr[x+1][y]=='O')
return true;
}//如果隔壁没有摆放积木,那么只要遍历到隔壁积木位置的前面列也没有放置积木就符合条件
if(arr[x][y-1]!='O'&&((x==m-1)||(arr[x+1][y]=='O'))){
for(int i=0;i<y-1;i++){
if(arr[x][i]=='O'){
return false;
}
}
return true;
}
}
return false;
}
void dfs(int x,int y){
if(x<0){//递归出口,即当到了最顶层的上层
if(fun()){//如果满足没有重复
sum++;
cout<<'('<<sum<<')'<<endl;
disp();
return ;
}
}else{
if(fun2(x,y)){//如果可以放置
arr[x][y]='O';//放置积木
if(y==n-1){//如果在最后一列
dfs(x-1,0);//就堆下一层
}else{
dfs(x,y+1);//不然就堆旁边
}
arr[x][y]='.';//不放积木
if(y==n-1){
dfs(x-1,0);
}else{
dfs(x,y+1);
}
}else{
if(y==n-1){
dfs(x-1,0);
}else{
dfs(x,y+1);
}
}
}
}
int main(){
cin>>m>>n;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin>>arr[i][j];
}
}
for(int i=0;i<n;i++){//从最底层的每一个位置开始堆积木
if(arr[m-1][i]=='.'){
dfs(m-1,i);
}
}
cout<<sum%1000000007<<endl;
return 0;
}