DeBruijin
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 321 Accepted Submission(s): 205
Problem Description
旋转鼓的表面分成m块扇形,如图所示(m=8)。图中阴影区表示用导电材料制成,空白区用绝缘材料制成,终端a、b和c是3(k=3)处接地或不是接地分别用二进制信号0或1表示。因此,鼓的位置可用二进制信号表示。试问应如何选取这8个扇形的材料使每转过一个扇形都得到一个不同的二进制信号,即每转一周,能得到000到111的8个数。
那我们现在把旋转鼓的表面分成m块扇形,每一份记为0或1,使得任何相继的k个数的有序组(按同一方向)都不同,对固定的k,m最大可达到多少,并任意输出符合条件的一个这样的有序组。
那我们现在把旋转鼓的表面分成m块扇形,每一份记为0或1,使得任何相继的k个数的有序组(按同一方向)都不同,对固定的k,m最大可达到多少,并任意输出符合条件的一个这样的有序组。
Input
每个case输入一个数k (2<=k<=11),表示图中所示的abc这样的接地线的数量。
Output
每个case输出m所能达到的最大值 ,并且输出字典序最小的一个符合条件的有序组,中间用空格隔开。Case间没有空行。有序组输出的格式为:00010111(k=3,只输出一个周期(0001011100010111……),并且首尾刚好是相接的)。
Sample Input
3
Sample Output
8 00010111
Source
和上一题一样,其实,000到001,其实00是不变的,可以抽象成点,而000,001都是只有一个,可以抽象成边,那么这题就可以做出来了,以0——2^(n-1)-1为编号建立一棵树,共2^(n-1)个节点,如果在某个节点后面添加一个0或者1,再去掉最高位,得到下一个节点,两节点之间连一条有向边。图中每条边就表示了一个数,共有2^n个数,各不相同!题目要求字典序最小,则从2^(n-1-1节点开始,并且每个节点先连加0的边,后连加1的边,这样的话,就能保证最终的字典序最小。还是欧拉回路,都是一个模型,算法也就那个一个。只是这里,为什么,我取模了,提交OJ反而会快10几Ms,这一点,我不明白的!
#include <iostream>
#include<stdio.h>
#include<vector>
using namespace std;
struct tree{
int v;
int id;
int to;
int flag;
};
int step;
vector<tree > p[35000];
bool re[35000];
int path[35000];
void dfs(int u)
{
for(int i=0;i<p[u].size();i++)
{
if(!re[p[u][i].id])
{
re[p[u][i].id]=true;
dfs(p[u][i].to);
path[step++]=p[u][i].flag;
}
}
}
int main()
{
int i,k,n,tt;
tree temp;
while(~scanf("%d",&k))
{
n=1<<(k-1);
// printf("%d n\n",n);
for(i=0;i<=n;i++)
p[i].clear();
for(i=0;i<n;i++)
{
tt=((i<<1)-((i&(1<<(k-2)))<<1));
// printf("%d tt\n",tt);
tt=tt%n;
temp.to=tt;
temp.id=i<<1;
temp.v=i;
temp.flag=0;
p[i].push_back(temp);
re[temp.id]=false;
tt+=1;
//printf("%d tt\n",tt);如果是从反着建,就要从0开始DFS了这一点要注意
tt=tt%n;
temp.v=i;
temp.to=tt;
temp.id=i<<1|1;
temp.flag=1;
re[temp.id]=false;
p[i].push_back(temp);
}
step=0;
dfs(n-1);
printf("%d ",n<<1);
for(i=step-1;i>=0;i--)
{
printf("%d",path[i]);
}
printf("\n");
}
return 0;
}