n<=20,显然要状压DP,将排队的状态压成一个数来表示
对于一个队伍状态S,令F[S][k]表示S状态违反了k条矛盾的合法方案数,则有
F[S|2i-1][k+num(S&power[i])]=F[S|2i-1][k+num(S&power[i])]+F[S][k]
其中i表示某个不在队伍的人,num(i)表示i在二进制下1的个数,power[i]表示必须排在i后面的人的情况。
(实际操作中发现power[i]储存排在i后面的人的情况的时候运行速度远不及power[i]储存排在i前面的情况)
1 #include<cstdio>神奇的代码
2 using namespace std;
3 const int qaq=1000000007;
4 int f[1<<20][21],power[21],n,m,t;
5 int main(){
6 freopen("count.in","r",stdin);
7 freopen("count.out","w",stdout);
8 scanf("%d%d%d",&n,&m,&t);
9 int u,v;
10 for (int i=1;i<=m;i++){
11 scanf("%d%d",&u,&v);
12 power[u]|=1<<(v-1); //power[v]|=1<<(u-1);
13 }
14 f[0][0]=1;
15 for (int i=0;i<(1<<n);i++)
16 for (int j=0;j<=t;j++)
17 if (f[i][j])
18 for (int k=1;k<=n;k++)
19 if ((i&(1<<(k-1)))==0){
20 int qwq=power[k]&i; //int qwq=power[k]^(power[k]&i);
21 int sum=0;
22 while (qwq){
23 sum++;
24 qwq&=(qwq-1);
25 }
26 if (j+sum<=t){
27 f[i|(1<<(k-1))][j+sum]+=f[i][j];
28 if (f[i|(1<<(k-1))][j+sum]>=qaq)
29 f[i|(1<<(k-1))][j+sum]%=qaq;
30 }
31 }
32 int ans=0;
33 for (int i=0;i<=t;i++)
34 ans=(ans+f[(1<<n)-1][i])%qaq;
35 printf("%d\n",ans);
36 return 0;
37 }
注意运算优先级,注意运算优先级,注意运算优先级!!!