原文链接:https://blog.csdn.net/u013480600/article/details/30315289
1.当前被选的字母必须有效(即mark[i]==true)且当前被选的字母vis=false(即还没被选)。
2.当我们从前到后依次选择一个字母x放进topo数组的时候,我们要保证在topo数组的当前位置cnt的前面那些位置中不会出现y这种字母。其中y<x,即y被要求出现在x后面。
3.可能有人会有疑问,就算保证了x出现在它的所有后继前面,但是你没有保证z(z>x)出现在x前面啊,那如果已经选了x的时候还没选z,怎么能形成合法的序列呢?
解答:当选了x时还没选z的话,在之后的递归中,标记当前位置的cnt就不可能==n,所以dfs不会产生一个可行解,这个dfs就无疾而终了。也就是说程序会自动忽略这种非法解。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=30;
const int maxm=500;
int n;//有效字母数
int G[maxn][maxn];
int vis[maxn];
int ans[maxn];
int cnt;
bool mark[maxn];//标记当前字母出现在变量中
bool ok(int i,int cnt)//如果在ans[0,cnt-1]出现了一个本应在i后面才出现的字母,那么返回false
{
for(int j=0;j<cnt;j++)
if(G[i][ans[j]]) return false;
return true;
}
void dfs(int cnt)
{
if(cnt==n)
{
for(int i=0;i<n;i++)
printf("%c",ans[i]+'a');
printf("\n");
}
else for(int i=0;i<26;i++)
if(mark[i]&&!vis[i]&&ok(i,cnt)){
vis[i]=1;
ans[cnt]=i;
dfs(cnt+1);
vis[i]=0;
}
}
int main()
{
char str[1000];
while(gets(str))
{
n=0;
memset(mark,0,sizeof(mark));
memset(G,0,sizeof(G));
memset(vis,0,sizeof(vis));
for(int i=0;str[i];i++)
if(str[i]!=' ')
mark[str[i]-'a']=true, n++;
gets(str);
for(int i=0;str[i];i++)
if(str[i]!=' '){
int a,b;
a=str[i++]-'a';
while(str[i]==' ')
i++;
b=str[i]-'a';
G[a][b]=1;
}
dfs(0);//表示当前正在构造第0个位置
puts("");
}
return 0;
}