题目大意:
某人要对拳皇的人物做一个排序。输入一个N,接下来N行每行两个字符串A B,表示A比B厉害。要求一共有多少种不同的拓扑排序方法。若不能完成排序输出0。
分析:
dp[S] (S表示点是否被取出的状态):得到S状态的方案数
dp[S|(1<< k)]+=dp[S] => 在S状态下,入度为0的点记为k
初始状态:dp[0]=1
目标状态:dp[(1<< n)-1]
#include<cstdio>
#include<cstring>
#define MAXN 20
#define MAXL 10
struct node{
int v;
node *next;
}edge[MAXN*200+10],*adj[MAXN+10],*ecnt=&edge[0];
int m,n,dp[(1<<MAXN)+10],in[MAXN+10];
char st[MAXN*16+10][MAXL+10];
void Init(){
memset(adj,0,sizeof adj);
ecnt=&edge[0];
memset(st,0,sizeof st);
n=0;
}
int Get_id(char *s){
for(int i=1;i<=n;i++)
if(!strcmp(st[i],s))
return i;
strcpy(st[++n],s);
return n;
}
void addedge(int u,int v)
{
node *p=++ecnt;
p->v=v;
p->next=adj[u];
adj[u]=p;
}
void read()
{
char s[MAXL+10],t[MAXL+10];
for(int i=1;i<=m;i++){
scanf("%s%s",s,t);
int p=Get_id(s),q=Get_id(t);
addedge(p,q);
}
}
void check(int S)
{
memset(in,0,sizeof in);
for(int i=1;i<=n;i++){
if(S&(1<<(i-1)))
continue;
for(node *p=adj[i];p;p=p->next)
if(!(S&(1<<(p->v-1))))
in[p->v]++;
}
}
void DP()
{
int S=(1<<n)-1;
memset(dp,0,sizeof dp);
dp[0]=1;
for(int i=0;i<=S;i++){
check(i);
for(int j=1;j<=n;j++)
if(!(i&(1<<(j-1)))&&!in[j])
dp[i|(1<<(j-1))]+=dp[i];
}
printf("%d\n",dp[S]);
}
int main()
{
while(scanf("%d",&m)==1){
Init();
read();
DP();
}
}