题目描述:
一天,抽屉从鲍勃那里得到了 n 个不同的牌子,每个牌子上都写了一个数字 ai(牌子上的数字可以相同)。高兴的抽屉把这些牌子排成一排,但他并不想牌子显得混乱。具体来说,若任意两个相邻的牌子上的数字相差超过 K,这些牌子就会显得很混乱。那么,有多少种不同的排列方案使得这些牌子显得混乱呢?两种方案不同且仅当某个牌子的摆放位置不同。
Solution
(由于太久没写状压的题了。。今天写一篇博客巩固一下。。)
数据范围中n最多是16,而这个题目又是一个放数问题,就很显然是一个状压了。
设
f
[
S
]
[
i
]
f[S][i]
f[S][i]表示目前放牌状态为
S
S
S,最后一张牌为第
i
i
i张的方案数。
为什么要设这个状态呢?由于题目中给了一个限制条件,就是相邻的两个数相差不能超过
k
k
k。
这样枚举状态就好转移了:
f
[
S
]
[
i
]
+
=
f
[
S
−
(
1
<
<
i
−
1
)
]
[
j
]
(
i
,
j
∈
S
且
a
b
s
(
a
[
j
]
−
a
[
i
]
)
>
k
)
f[S][i]+=f[S-(1<<i-1)][j]\ \ (i,j\in S且abs(a[j]-a[i])>k)
f[S][i]+=f[S−(1<<i−1)][j] (i,j∈S且abs(a[j]−a[i])>k)
答案就是 ∑ i = 1 n f [ 1 < < ( n ) − 1 ] [ i ] \sum_{i=1}^{n} f[1<<(n)-1][i] ∑i=1nf[1<<(n)−1][i]
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 17;
int f[1<<N][N];
int a[N];
int n,k;
signed main(){
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
scanf("%lld %lld",&n,&k);
for (int i = 1; i <= n; i++) scanf("%lld",&a[i]) , f[1<<i-1][i] = 1;
for (int S = 1; S < 1<<n; S++)
for (int i = 1; i <= n; i++)
if (S & (1<<i-1))
for (int j = 1; j <= n; j++)
if (S & (1<<j-1) && i!=j && abs(a[i] - a[j])>k) f[S][i]+=f[S - (1<<i-1)][j];
int ans = 0;
for (int i = 1; i <= n; i++) ans+=f[(1<<n)-1][i];
printf("%lld",ans);
return 0;
}