原题大意
艺术团中,有n个舞者,i舞者和(i-1)舞者、(i+1)舞者相似,(i-1)和(i+1)舞者并不相似。如果n> 1,那么第一个舞者只有相似的舞者,最后一个舞者只有相似的舞者,所有其他舞者都有两个相似的舞者。
舞蹈开始和结束在一个空荡荡的舞台。舞蹈舞蹈不应该是空的。每一分钟,以下变化之一发生在舞台上:
1.一个舞者(目前不在舞台上)出现;
2.一个舞者(目前在舞台上)离开舞台;
3.一个舞者代替另一个类似于他/她的舞者(基于舞者的切换-一个舞者离开舞台,而舞台上出现一个类似的舞者)
同时,舞台上不能有超过k个舞者。
现在编舞师正在考虑安排舞蹈,使得每一个不包含k个舞者的舞者都会在舞台上出现一次。你的工作是编写一个程序来帮助编舞。
输出:
+i表示i舞者出现在舞台上,-i表示i舞者离开舞台;
++i表示i舞者离开舞台,同时(i+1)舞者出现在舞台上;
–i表示i舞者离开舞台,同时(i-1)舞者出现在舞台上
算法分析
题目要我们生成组合 && 相邻的两个组合必须很接近由这
点,我们可以想到Gray码。
注意到台上的人数不能超过k。这和格雷码说好的不一样啊!
其实,如果我们把n阶格雷码中,1的个数大于k的元素删除
就会得到符合要求的序列。比较序列中相邻的两个元素,即
可得出操作。
程序代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
vector<int> vc;
int n,k;
void to_gray(ll x){
int cnt = 0;
ll ans = x^(x>>1);
cnt = __builtin_popcount(ans);
/* while(ans){
if(ans&1) cnt++;
ans >>= 1;
}*/
if(cnt > k) return;
return vc.push_back(x^(x>>1));
}
void cmp(int x, int y){
int tmp = x^y;
int plus = 0;
int substr = 0;
for(int i = 0; i < n; i++)
{
if((1<<i)&tmp){
if((1<<i)&x) substr = i+1;
if((1<<i)&y) plus = i+1;
}
}
if(plus && !substr) printf("+%d", plus);
if(!plus && substr) printf("-%d", substr);
if(plus && substr)
{ if(plus > substr)
printf("++%d", substr);
else
printf("--%d", substr);
}
}
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d%d",&n, &k);
for(int i = 0; i < (1<<n); i++)
to_gray(i);
for(int i = 1; i < vc.size(); i++)
cmp(vc[i-1],vc[i]);
printf("-%d", n);
return 0;
}