洛谷 P2915 [USACO08NOV]奶牛混合起来Mixed Up Cows 题解

洛谷 P2915 [USACO08NOV]奶牛混合起来Mixed Up Cows 题解

2019-10-30 xiaoh

题意

有n头牛(4<=n<=16),第i头牛的身高为si。求满足任意相邻的两头牛身高差都大于给定常数k(1<=k<=3400)的排列的数量

思路

瞄到的第一眼注意到了数据。4<=n<=16!!!这数据有点小的离谱了吧!很明显,只有两种可能:一是爆搜,而是状压
心中默默一算,暴力n!差不多在1e13多一点,就算剪枝也没什么卵用。所以显然是记搜或状压(其实是一个玩意)QAQ 再算算复杂度,O(nn * 2^n),大概是81e6左右吧。正好!所以基本状压实锤了。
既然是状压,那算法也就很明显了吧。定义dp[i][j],i为是否取每一头牛的状态压缩,j为当前最后一头牛的编号。那么我们只要先i从1取到2^n-1,每次j从1跑到n表示当前的最后一头牛的编号,先判断是否合法,若合法的话,在把l从1跑到n,表示倒数第二头牛的编号(即枚举前一种情况的所有可能解),如果l合法且j,l的身高差大于k的话,就把当前的答案加上前一种情况的解的数量就好啦QAQ
(热烈庆祝状压编码时间第一次<30min,并且一次过)

Code

#include<bits/stdc++.h>
using namespace std;
inline int read()//快读
{
	int ret=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
	return ret;
}
int n,k;
int s[20];
long long dp[1<<20][20];
long long ans=0;
int main()
{
	n=read(),k=read();
	for(int i=1;i<=n;i++) s[i]=read();
	for(int i=1;i<=n;i++) dp[1<<(i-1)][i]=1;//初始化
	for(int i=1;i<(1<<n);i++)
	{
		if(!(i&(i-1))) continue;
		for(int j=1;j<=n;j++)//遍历前一种情况并计算
		if(i&(1<<(j-1)))
		for(int l=1;l<=n;l++)
		if(i&(1<<(l-1))&&abs(s[j]-s[l])>k)
		dp[i][j]+=dp[i^(1<<(j-1))][l];
	}
	for(int i=1;i<=n;i++) ans+=dp[(1<<n)-1][i];
	printf("%lld\n",ans);
}
原文地址:https://www.cnblogs.com/xiaoh105/p/12104553.html