链接:登录—专业IT笔试面试备考平台_牛客网 混乱的奶牛 [Don Piele, 2007] Farmer John的N(4 <= N <= 16)头奶牛中的每一头都有一个唯一的编号S_i (1 <= S_i <= 25,000). 奶牛为她们的编号感到骄傲, 所以每一头奶牛都把她的编号刻在一个金牌上, 并且把金牌挂在她们宽大的脖子上. 奶牛们对在挤奶的时候被排成一支”混乱”的队伍非常反感. 如果一个队伍里任意两头相邻的奶牛的编号相差超过K (1 <= K <= 3400), 它就被称为是混乱的. 比如说,当N = 6, K = 1时, 1, 3, 5, 2, 6, 4 就是一支”混乱”的队伍, 但是 1, 3, 6, 5, 2, 4 不是(因为5和6只相差1). 那么, 有多少种能够使奶牛排成”混乱”的队伍的方案呢?
其实这个有点类似于TSP的思路,都是通过枚举当前和上一次的点来进行递推。
(话说这个题的状压也许并不是那么好想?)
思路:数据范围不大,应该说是异常的小,一般这种东西就应该往类似状压或者暴力的方向上去想了。
dp[i][j]:状态为j且队尾为i的情况下可行的方案数 ;
下一步考虑初始化:很明显应该在只放一头牛的情况下进行初始化,对于任意一头牛,它第一个放进去的时候,它就是队尾,并且此时可行数也只有1(毕竟只能放一头);
for(int i=1;i<=n;++i) dp[i][1<<(i-1)]=1; //初始化
然后枚举所有状态,在所有可能的状态中,先任选一个已经被标为1(也就是已经在队伍里的牛)作为队尾,找到队尾后,再在标记为0(也就是还没进队)的牛中选一个插进来,如果这两头牛的编号满足要求(差的绝对值大于要求),这就是一个可行的方案了。
最后的状态一定是全为1的情况,那么把每头牛作为队尾的情况对应的方法数加起来就是了。
(如果想到状压的话还是比较裸的)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,s;
ll mas[20];
ll dp[20][(1<<18)+10];//状态为j且队尾为i的情况下可行的方案数
int main()
{
cin>>n>>s;
for(int i=1;i<=n;++i) cin>>mas[i];
for(int i=1;i<=n;++i) dp[i][1<<(i-1)]=1; //初始化
for(ll i=0;i<(1<<n);++i){
for(int j=1;j<=n;++j){
if(i&(1<<(j-1))){
for(int k=1;k<=n;++k){
if((i&(1<<(k-1)))) continue;
if(abs(mas[j]-mas[k])<=s) continue;
dp[k][i+(1<<(k-1))]+=dp[j][i];
}
}
}
}
ll ans=0;
for(int i=1;i<=n;++i){
ans+=dp[i][(1<<n)-1];
}
cout<<ans<<endl;
return 0;
}
|