给出N行英雄的比较,每一行包含两个英雄的名字,代表第一个英雄比第二个英雄更受欢迎。
英雄的数目不超过16个。问有多少种可能的受欢迎程度的序列满足N行英雄的比较。
由于只有英雄数目不超过16个,可以用二进制来解决。
x的的位表示还有哪些点没有处理。在这些点中选择一个入度没零的点,求剩下的点可能排列的数目。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <string> 7 #include <vector> 8 #include <set> 9 #include <map> 10 #include <queue> 11 #include <stack> 12 #include <list> 13 using namespace std; 14 const int INF=0x5fffffff; 15 const double EXP=1e-8; 16 const int MS=1<<17; 17 int edges[18][18]; 18 int in[18]; 19 int base[18]; 20 int flag[MS]; 21 char name[18][15]; 22 int n,m; 23 24 int ID(char *s) 25 { 26 for(int i=0;i<n;i++) 27 { 28 if(!strcmp(name[i],s)) 29 return i; 30 } 31 strcpy(name[n],s); 32 return n++; 33 } 34 35 int find(int x) //x的二进制的位表示那些点还没有处理。 36 { 37 if(flag[x]>0) 38 return flag[x]; 39 for(int i=0;i<n;i++) 40 { 41 if(in[i]==0&&((x&base[i])==base[i])) 42 { 43 for(int j=0;j<n;j++) 44 if(edges[i][j]) 45 in[j]--; 46 flag[x]+=find(x^base[i]);// 去掉i点后,剩下的点有多少种可能 47 for(int j=0;j<n;j++) 48 if(edges[i][j]) 49 in[j]++; 50 } 51 } 52 return flag[x]; 53 } 54 55 int main() 56 { 57 char a[15],b[15]; 58 for(int i=0;i<17;i++) 59 base[i]=1<<i; 60 while(scanf("%d",&m)!=EOF) 61 { 62 n=0; //顶点数量 63 int c,d; 64 memset(flag,0,sizeof(flag)); 65 memset(edges,0,sizeof(edges)); 66 memset(in,0,sizeof(in)); 67 for(int i=0;i<m;i++) 68 { 69 scanf("%s%s",a,b); 70 c=ID(a); 71 d=ID(b); 72 edges[c][d]=1; 73 in[d]++; 74 } 75 for(int i=0;i<n;i++) 76 flag[base[i]]=1; 77 int ans=find(base[n]-1); 78 printf("%d\n",ans); 79 } 80 return 0; 81 }
时间: 2024-11-15 15:34:28