状压dp水题
俗话说:能打暴力的都是简单题,因为你可以用暴力来对拍啊!那么只要你足够强,你就能写出一个正解而不出现WA。
暴力做法就是直接枚举全排列,一个一个算即可。
正解是定义dp[i][j]
为最后一个元素为\(i\),选中的状态为\(j\)的方案数。转移很显然,太显然了。不说了。
所以最后把\(\sum{dp[i][S]}\)加起来就可以了。
但是,我做状压dp的时候总会有些奇奇怪怪的现象,以至于莫名其妙算不出答案。
这个时候,换一下枚举的顺序!!!
其实我之前也出现过这样的经历,递推顺序错直接爆零,顺序对直接AC
然后我就愉快地AC了。
代码:
#include<cstdio>
#include<algorithm>
#define ll long long
const int maxn = 17, maxN = 65537;
ll dp[maxn][maxN];// 以i为最后一位,状态为j的方案数
ll a[maxn];
int n, m;
int S;
void init()
{
for(int i = 1; i <= n; i++) dp[i][1 << (i - 1)] = 1;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
init();
S = (1 << n) - 1;
for(int j = 1; j <= S; j++)
{
for(int i = 1; i <= n; i++)
{
if((1 << (i - 1)) & j)
{
for(int k = 1; k <= n; k++)
{
if((1 << (k - 1)) & j) continue;
if(abs(a[i] - a[k]) > m) dp[k][j | (1 << (k - 1))] += dp[i][j];
}
}
}
}
ll ans = 0;
for(int i = 1; i <= n; i++) ans += dp[i][S];
printf("%lld\n", ans);
return 0;
}