问题描述
有一长度为N(1<=N<=10)的地板,给定三种不同瓷砖:一种长度为1,一种长度为2,另一种长度为3,数目不限。要将这个长度为N的地板铺满,并且要求长度为1的瓷砖不能相邻,一共有多少种不同的铺法?在所有的铺设方法中,一共用了长度为1的瓷砖多少块?
例如,长度为4的地面一共有如下4种铺法,并且,一共用了长度为1的瓷砖4块:
4=1+2+1
4=1+3
4=2+2
4=3+1
编程求解上述问题。
例如,长度为4的地面一共有如下4种铺法,并且,一共用了长度为1的瓷砖4块:
4=1+2+1
4=1+3
4=2+2
4=3+1
编程求解上述问题。
输入格式
只有一个数N,代表地板的长度
输出格式
第一行有一个数,代表所有不同的瓷砖铺放方法的总数。
第二行也有一个数,代表这些铺法中长度为1的瓷砖的总数
第二行也有一个数,代表这些铺法中长度为1的瓷砖的总数
样例输入
4
样例输出
4
4
//#include<iostream>
//#include<cstdio>
#include<stdio.h>
//蓝色部分为调试时所写
int ans, num;
int cnt = 0, count = 0;
void dg(int x, int n1, short flag) {
//问题终于找出来了,对于n1的每次增加必须在确定本次所铺的瓷砖为1时, 然后在下一次进行增加,否则会导致本次可能多次自增
if(x == 0 && !flag) {ans++; num += n1; /*cout << "第" << ++count << "次成功------"<< "n1: " << n1 << "出栈" << endl; */return ;}
else if(x == 0 && flag) {n1++; ans++; num += n1; return ;}
//cout <<"第" << ++cnt << "次 n1: " << n1 << " flag: " << flag << " ans: " << ans << endl;
if(flag) n1++;
for(int i = 1; i <= 3; i++)
if(x >= i) { // cout << "i -- " << i << endl;
if( i == 1 && !flag) {flag = 1;/*cout << "入栈 " ;*/dg(x-i, n1, flag);}
else if(i == 1 && flag) ;
else {flag = 0; /*cout << "入栈 " ;*/dg(x-i, n1, flag);}
}
// cout << " 出栈 " << endl; 一次函数的结束会减少一个栈帧,勉强写为"出栈"
}
int main() {
int N;
while(scanf("%d", &N) != EOF) {
ans = num = 0;
dg(N, 0, 0);
printf("%d\n%d\n", ans, num);
}
return 0;
}
//2016/3/16日更新....
本题思路重新整理(暴力法):
从总和为0开始:每一层次有三种选择(1 2 3),终止状态为达到目标总和N。没有什么恶心人的WA点。
时隔一年,又重温了一遍这题,居然又写了一个半小时,卡在一个dfs到底是vis++还是vis+1的问题上了,下面见代码:
优化的AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int N;
int ans, cas;
//1 2 3
void dfs(int cur, int flag, int vis) {
if(cur > N) return ;
if(cur == N) {
cas++; ans += vis; return ;
}
for(int i = 1; i <= 3; i++) {
if(flag && i != 1) dfs(cur+i, !flag, vis);
else if(!flag) dfs(cur+i, i==1?!flag:flag, i==1?vis+1:vis);
}
}
int main() {
cin >> N;
ans = 0; cas = 0;
dfs(0, 0, 0);
cout << cas << endl; //方案的个数
cout << ans << endl; //1的个数
return 0;
}
之前写错的代码:(仔细观察,上面是vis+1,下面的是vis++,两者区别很大,vis++会导致vis变量当前状态改变以至于影响到同一层次的后面的状态, 而vis+1则不会!!这依旧是初学者的毛病。。。)
错误代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int N;
int ans, cas;
//1 2 3
void dfs(int cur, int flag, int vis) {
if(cur > N) return ;
if(cur == N) {
cas++; ans += vis; return ;
}
for(int i = 1; i <= 3; i++) {
if(flag && i != 1) dfs(cur+i, !flag, vis);
else if(!flag) dfs(cur+i, i==1?!flag:flag, i==1?vis++:vis);
}
}
int main() {
cin >> N;
ans = 0; cas = 0;
dfs(0, 0, 0);
cout << cas << endl;
cout << ans << endl;
return 0;
}