P2915 [USACO08NOV]Mixed Up Cows G 题解

首先依然观察到$N=16$,肯定是状压奶牛。

为了避免后效性,我们发现对于一个奶牛是否能在某个位置只和它前一个奶牛和后一个奶牛有关

因此我们可以设$f(i,state)$表示奶牛状态为$state$(1为在序列中0为不在),当前以后排好队的奶牛的最后一个为$i$的方案数

那么$f(i,state)=\sum{f(j,state\oplus 1<<(i-1))}, i,j \in state$

主要提供一个转移的方法

我们可以发现拓扑序应为$0000$  $0001$ $0010$ $0100$ $1000$ $0011$ $0110$ $0101$.......

也就是先一个$1$再两个$1$....

实现起来比较困难

事实上我们可以直接从0自加到$2^n-1$,这样也是满足拓扑序的

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 using namespace std;
 7 inline int r()
 8 {
 9     int s=0,k=1;char c=getchar();
10     while(!isdigit(c))
11     {
12         if(c=='-')k=-1;
13         c=getchar();
14     }
15     while(isdigit(c))
16     {
17         s=s*10+c-'0';
18         c=getchar();
19     }
20     return s*k;
21 }
22 int n,m,a[101],f[66666][101];//状态 最后一个 
23 bool b[66666];
24 signed main()
25 {
26     n=r();m=r();
27     for(int i=1;i<=n;i++)
28     {
29         a[i]=r();
30     }
31     for(int i=1;i<=n;i++)
32     {
33         f[1<<(i-1)][i]=1;
34     }
35     for(int i=0;i<=(1<<n)-1;i++)
36     {
37         if(b[i])continue;
38         for(int j=1;j<=n;j++)//当前最后一个 
39         {
40             if(!(i&(1<<(j-1))))continue;
41             for(int k=1;k<=n;k++)//前一个的最后一个 
42             {
43                 if(!(i&(1<<(k-1))))continue;
44                 if(j==k)continue;
45                 if(abs(a[j]-a[k])<=m)continue;
46                 f[i][j]+=f[i^(1<<(j-1))][k];
47             }
48         }
49         
50     }
51     int ans=0;
52     for(int i=1;i<=n;i++)
53     {
54         ans+=f[(1<<n)-1][i];
55     }
56     cout<<ans;
57 }
View Code

 

posted @ 2021-07-12 08:26  lei_yu  阅读(21)  评论(0编辑  收藏  举报