状压$dp$:
本蒟蒻被动规虐的死去活来,于是决定死磕$dp$了!以前看到$dp$立刻走人。。
这篇文章可能对新手不太友好,二进制这种我就不讲了,主要是为了方便自己记忆(对不起$qwq$)
进入正题:
首先,如何判断某些题目是不是状压$dp$呢,要看$n$的取值范围,当较小的时候,就可以考虑状压了。
那么我们设$f[j][i]$表示以第$j$头牛结尾,也就是最后一次加入队列的是第$j$头牛,并且现在队列状态为$i$的时候的方案数。
那么我们考虑现在要加入第$k$头奶牛,那么我们需要考虑一下几种情况:
$1、$第$j$头奶牛与新加的第$k$头奶牛相差不超过题目要求的时候,要排除
$2、$状态中第$j$头奶牛这个位置要为$1$,因为$j$既然是最后加入的,那肯定在队列中
$3、$状态中第$k$头奶牛这个位置要为$0$,因为你要加入他。
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#define int long long
#define N 20
using namespace std;
int n,m;
int val[N],f[N][1<<N];
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
scanf("%lld",&val[i]);
for(int i=1;i<=n;++i)
f[i][1<<(i-1)]=1;
for(int i=1;i<(1<<n);++i)
for(int j=1;j<=n;++j)
for(int k=1;k<=n;++k)
{
if(((1<<(j-1))&i)==0||((1<<(k-1))&i)||abs(val[k]-val[j])<=m)
continue;
f[k][i+(1<<(k-1))]+=f[j][i];
}
int ans=0;
for(int i=1;i<=n;++i)
ans+=f[i][(1<<n)-1];
printf("%lld",ans);
return 0;
}