入门需知:
左移一位: x << 1
右移N位: x >> N
取出最右边的1: x & (-x)
把最右边的1变为0: x & (x-1)
把右数第k位取反: x ^ (1<<(k-1))
1、往一个给定的状态加入某元素 i|(1<<j)
2、检查某元素是否存在于当前状态中 i&(1<<j)
3、 从一个状态中删除一个元素 i=(i^(1<<j))
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
long long dp[1<<16][16];//dp[i][j],i表示集合的状态,j表示集合中最后一个元素
int a[16];
int main()
{
freopen("in.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
int i,j,k;
for(i=0;i<n;i++)
scanf("%d",&a[i]);
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
dp[1<<i][i]=1; //初始化,集合只有1个元素且每个元素以自己结尾的个数为1
for(i=0;i<(1<<n);i++)
{
for(j=0;j<n;j++)
{
if((i&(1<<j))&&dp[i][j])//集合中有j,且以j结尾
{
for(k=0;k<n;k++)
{
if(!(i&(1<<k))&&abs(a[j]-a[k])>m)//集合中无k,并且可以插入到j后面
dp[i|(1<<k)][k]+=dp[i][j];//将K插入j的后面,此时k是新的结尾
}
}
}
}
long long ans=0;
for(i=0;i<n;i++)
ans+=dp[(1<<n)-1][i];//集合中所有元素都存在 即111111..111时,以任意一个数结尾的个数相加就是总个数
printf("%lld\n",ans);
}
return 0;
}