HDU 2894 DeBruijin (数位欧拉)

Posted Yeader

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 2894 DeBruijin (数位欧拉)相关的知识,希望对你有一定的参考价值。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2894

题目大意:旋转鼓的表面分成m块扇形,如图所示(m=8)。图中阴影区表示用导电材料制成,空白区用绝缘材料制成,终端a、b和c是3(k=3)处接地或不是接地分别用二进制信号0或1表示。因此,鼓的位置可用二进制信号表示。试问应如何选取这8个扇形的材料使每转过一个扇形都得到一个不同的二进制信号,即每转一周,能得到000到111的8个数。

技术分享图片


那我们现在把旋转鼓的表面分成m块扇形,每一份记为0或1,使得任何相继的k个数的有序组(按同一方向)都不同,对固定的k,m最大可达到多少,并任意输出符合条件的一个这样的有序组。

Input
每个case输入一个数k (2<=k<=11),表示图中所示的abc这样的接地线的数量。
Output
每个case输出m所能达到的最大值 ,并且输出字典序最小的一个符合条件的有序组,中间用空格隔开。Case间没有空行。有序组输出的格式为:00010111(k=3,只输出一个周期(0001011100010111……),并且首尾刚好是相接的)。
解题思路:参考链接

第一问m达到的最大值为2^k。

第二问就是模拟一下旋转鼓接地线的旋转过程,每次旋转即删去第一个数,然后在最后加一个0(a<<1&((1<<k)-1))或1(a<<1&((1<<k)-1)+1),同时标记出现过的数字,保证每个出现的数字都不同。

因为所有数为0到2^k-1,对于任意给定的点a,将它与点a1=a<<1&((1<<k)-1)与点a2=a1+1分别连一条边,构成欧拉回路(每个点入度=出度=2),加一个vis数组确定每个数出现一次。因为结果需要按照字典序从小到大排,所以首先输出的必然是k个前导0,然后dfs判断0或1时先判0,再判1,逆序输出即可(dfs回溯)。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define CLR(arr,val) memset(arr,val,sizeof(arr))
 5 using namespace std;
 6 const int N=15;
 7 
 8 int k,cnt;
 9 int ans[1<<N];
10 bool vis[1<<N];
11 
12 void init(){
13     CLR(vis,false);
14     CLR(ans,0);
15     cnt=0;
16 }
17 
18 void euler(int st) {
19     int s1=(st<<1)&((1<<k)-1);
20     int s2=s1+1;
21     if (!vis[s1]){
22         vis[s1]=1;
23         euler(s1);
24         ans[++cnt]=0;
25     }
26     if (!vis[s2]) {
27         vis[s2]=1;
28         euler(s2);
29         ans[++cnt]=1;
30     }
31 }
32 
33 int main(){
34     while(~scanf("%d",&k)){
35         init();
36         euler(0);
37         printf("%d ",cnt);
38         //因为要求字典序最小,所以前k位都是0(前导零)
39         for(int i=1;i<k;i++){
40             printf("0");
41         }
42         for(int i=cnt;i>=k;i--){
43             printf("%d",ans[i]);
44         }
45         printf("\n");
46     }
47     return 0;
48 }

 

以上是关于HDU 2894 DeBruijin (数位欧拉)的主要内容,如果未能解决你的问题,请参考以下文章

欧拉(回)路

欧拉图目录

欧拉图目录

经典欧拉回路应用——旋转鼓轮模型

经典欧拉回路应用——旋转鼓轮模型

hdu1878欧拉回路(DFS+欧拉回路)