思路:
记忆化搜索。
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstring>
#include <limits.h>
#define Long long long
#define uint unsigned int
#define N
#define mod 1000000007
#define inf 100000000
#define eps 1e-10
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Dor(i,r,l) for(int i=r;i>=l;i--)
using namespace std;
ifstream in("/Users/urey/data/input.txt");
//_________________________________________________________________________________
//题意:有一排n个插槽,每个插槽的高度可以为{1,2,3,4}. 求问: 排列中存在相邻两个插槽高度差为3 ,且使用了至少3种高度的情况有多少种
int n;//插槽个数
long long dp[50][5][2][4];
// @param i : 第几个槽
// @param high : 当前的槽高度
// @param k : 是否存在高度差为3的槽, 即必须有个1,有个4
// @parram diff : 使用了几种高度
// @parram s : 四种高度, eg: “1111” 表示四种高度都有
long long dfs(int i, int high, int exist, int diff, int status) {
if(dp[i][high][exist][diff] != -1) {
return dp[i][high][exist][diff];
}
if(i == n) {
if(exist == 1 && diff >= 3) {
return 1;
}else {
return 0;
}
}
long long ans = 0;
int tmp;
for(int d = 1; d <= 4; ++d) {//dfs四种高度
if(!(status & 1<<(d-1))) {//没用过这种高度
tmp = diff + 1;
}else {
tmp = diff;
}
tmp = min(tmp, 3);//剪枝,用过四种或三种高度都是“三种以上”
if(exist || ((d * high == 4) && d != high))
ans += dfs(i+1, d, 1, tmp, status | 1<<(d-1));
else
ans += dfs(i+1, d, 0, tmp, status | 1<<(d-1));
}
return dp[i][high][exist][diff] = ans;
}
int main(int argc, const char * argv[]) {
while(cin>>n) {
if(n == -1) return 0;
memset(dp, -1, sizeof(dp));
dfs(0, 0, 0, 0, 0);
cout<<n<<": "<<dp[0][0][0][0]<<endl;
}
return 0;
}