洛谷P2915 Usaco08 Mixed Up Cows

来源:互联网 发布:数据库冗余 编辑:程序博客网 时间:2024/05/16 13:41

标准的状压题!

所谓状态压缩就是将状态用二进制存储下来,并用位运算实现转移
用二进制存储,可以不重不漏地遍历到所有的状态

我们设0表示牛已在队伍中,1表示牛不在队伍中,最后需要求得全部为1的状态
设状态为f(i,j)表示第i头牛在队尾,队伍状态为j(一个二进制数)时的方案数

答案为n1f(i,(1111...1)2),这里(1111...1)2表示由n个1组成的二进制数

在讲到转移之前,有必要提一下位运算。将1左移N位,得到的二进制数其实是一个1后面带上N个0,这和我们需要的N个1不符

但是这个时候我们发现1000021=(1111)2
而位运算的优先级又是很低的,所以代码里就需要写成i<=(1<<n)-1

转移过程则是先从小到大地枚举队伍状态i(一个二进制数),再不断地向队尾添加元素。
枚举队尾j,再枚举一个可以和队尾相接的元素p,就可以得到转移方程:
f[p][i|(1<<p-1)] += f[j][i]

#include <algorithm>#include <iostream>#include <cstdio>using namespace std;#define debug(x) cerr << #x << "=" << x << endl;int a[20],n,k;long long f[20][1<<16],ans;int main() {    cin >> n >> k;    for(int i=1; i<=n; i++)         cin >> a[i];    for(int i=1; i<=n; i++)         f[i][1<<(i-1)] = 1;     for(int i=1; i<=(1<<n)-1; i++)        for(int j=1; j<=n; j++)            if(i&(1<<j-1))                for(int p=1; p<=n; p++)                     if(!(i&(1<<p-1)) && abs(a[p]-a[j]) > k)  //转移                         f[p][i|(1<<p-1)] += f[j][i];    for(int i=1; i<=n; i++)         ans += f[i][(1<<n)-1];    cout << ans << endl;    return 0;}