![](https://images2015.cnblogs.com/blog/912373/201611/912373-20161109175857358-1508244971.png)
![](https://images2015.cnblogs.com/blog/912373/201611/912373-20161109175916827-1008138296.png)
![](https://images2015.cnblogs.com/blog/912373/201611/912373-20161109175952358-1317997066.png)
![](https://images2015.cnblogs.com/blog/912373/201611/912373-20161109180011702-100298561.png)
源代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<string>
#define INF 10000007
using namespace std;
struct Node
{
int X,Y;
}i[6][37];
string S;
queue <string> Q;
int n,k,Sum[6]={0};
int Prime1[6]={13,11,7,5,3,2};
int Prime2[6]={17,19,23,29,31,37};
bool Flag(0),Vis1[10000007]={0},Vis2[10000007]={0};
int main() //我求的是什么,我不知道,但我求出了所有长度为n的可能的合并情况数。
{
scanf("%d%d\n",&n,&k);
for (int a=0;a<k;a++)
{
char t,t1,t2;
t1=getchar();
t2=getchar();
getchar();
t=getchar();
Sum[t-'a']++;
i[t-'a'][Sum[t-'a']].X=t1-'a';
i[t-'a'][Sum[t-'a']].Y=t2-'a';
getchar();
}
Q.push("a"); //字符串类型STL队列。
Vis1[13]=Vis2[17]=true;
while (!Q.empty()) //BFS注意条件,防止死循环。
{
S=Q.front();
Q.pop();
int L=S.length();
if (L==n) //后面的肯定更长,跳出。
{
Flag=true;
break;
}
char T[6]={0};
for (int a=0;a<L;a++)
{
int t=S[a]-'a',T1=1,T2=1;
for (int b=0;b<a;b++)
{
T[b]=S[b]; //算是string转char[]。
T1=T1*Prime1[S[b]-'a']%INF*(b+1)%INF; //双重哈希。
T2=T2*Prime2[S[b]-'a']%INF*(b+1)%INF;
}
for (int b=a+1;b<L;b++)
{
T[b+1]=S[b];
T1=T1*Prime1[T[b+1]-'a']%INF*(b+2)%INF;
T2=T2*Prime2[T[b+1]-'a']%INF*(b+2)%INF;
}
for (int b=1;b<=Sum[t];b++)
{
T[a]=i[t][b].X+'a';
T[a+1]=i[t][b].Y+'a';
int t1=T1,t2=T2;
T1=T1*Prime1[T[a]-'a']%INF*(a+1)%INF*Prime1[T[a+1]-'a']%INF*(a+2)%INF;
T2=T2*Prime2[T[a]-'a']%INF*(a+1)%INF*Prime2[T[a+1]-'a']%INF*(a+2)%INF;
if (!Vis1[T1]||!Vis2[T2])
{
string s(T); //char[]转string。
Vis1[T1]=Vis2[T2]=true;
Q.push(s);
}
T1=t1;
T2=t2;
}
}
}
if (Flag) //特判。
printf("%d",Q.size()+1);
else
printf("0");
return 0;
}
/*
倒着来,从"a"开始不断分裂,BFS所有情况即可。
读题还是要细心认真,不要吝惜时间。
血(WA)的教训!
*/