今天在群里面遇到了庆神提出的讨论题目:
一个只包含'A','B','C'的字符串 求当长度为n时 有多少种可能情况使该串中不包含'ABC'三个连在一起不分先后的子串
刚开始没什么思路,而且群里面讨论的很热烈,于是自己写了个爆搜
#include <iostream>
#include <queue>
#include <string>
using namespace std;
int built;
bool check(string& s)/// Return TRUE if No ERROR
{
if(s.size()<3) return true;
for(int i=0;i<=s.size()-3;i++)
{
int a=s.at(i);
int _x=s.at(i+1);
a^=_x;
_x=s.at(i+2);
a^=_x;
if(a==built) return false;
}
return true;
}
int main()
{
int n;
built='a';
int _x='b';
built^=_x;
_x='c';
built^=_x;
while(cin>>n)
{
queue<string> bus;
int cnt=0;
bus.push("a");
bus.push("b");
bus.push("c");
while(!bus.empty())
{
string s=bus.front();
bus.pop();
if(check(s))
{
if(s.size()==n)
{
cout<<s<<endl;
cnt++;
continue;
}
bus.push(s+"a");
bus.push(s+"b");
bus.push(s+"c");
}
}
cout<<cnt<<endl;
}
return 0;
}
得到了一些结果,保证这是正确的
后来开始思考别的方法,发现所要求内容只与连续的三个字符有关,因此可以DP,那么DP维度就是四维
dp[i][j][k][m]=
0 (j,k,m不相同)
sum{cc=0~3 | dp[i-1][cc][j][k] }
其中i表示字串长度,j,k,m表示从后数第三位,第二位,第一位
初始化从i=3进行,i<3的时候可以直接输出答案(爆搜得到的)
于是代码如下
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
#define foreach(ValName,From,Dest) for(int ValName=From;ValName<Dest;++ValName)
#define MAXN 35
long long dp[MAXN][3][3][3];
int main()
{
int n;
scanf("%d",&n);
/// i=3
foreach(j,0,3)
foreach(k,0,3)
foreach(m,0,3)
{
if(j!=k&&k!=m&&j!=m) dp[3][j][k][m]=0;
else dp[3][j][k][m]=1;
}
/// i=4 ... 30
foreach(i,4,n+1)
{
foreach(j,0,3)
{
foreach(k,0,3)
{
foreach(m,0,3)
{
if(j!=k&&k!=m&&j!=m)
{
dp[i][j][k][m]=0;
}
else
{
//dp[i][j][k][m]=dp[i-1][?][j][k];
long long ans=0;
foreach(cc,0,3)
{
ans+=dp[i-1][cc][j][k];
}
dp[i][j][k][m]=ans;
}
}
}
}
}
long long ans=0;
foreach(j,0,3)
foreach(k,0,3)
foreach(m,0,3)
ans+=dp[n][j][k][m];
printf("%I64d\n",ans);
}
写完之后发现其实初始化可以合并到求值里面去,不过结果都一样,就不写了。
发给庆神之后居然被回复啦!好开心!对话过程中无时无刻不能感受到庆神那种谦逊!真心让人佩服!