标签:二进制 space dfs回溯 http ges acm 逆序 代码 cstring
题目链接: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最大可达到多少,并任意输出符合条件的一个这样的有序组。
第一问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 }
标签:二进制 space dfs回溯 http ges acm 逆序 代码 cstring
原文地址:http://www.cnblogs.com/fu3638/p/7979259.html